Handle preference stores corruption by clearing them (#5086)

* Handle preference stores corruption by clearing them:
    - Use the centralised `PreferenceDataStoreFactory` instead of `preferences by`.
    - Add `DefaultPreferencesCorruptionHandlerFactory.replaceWithEmpty` to its `create(name)` method so all preference stores are cleared if they're corrupted.

* Add detekt rule to make sure we use `PreferenceDataStoreFactory` instead of `by preferencesDataStore`

* Remove `@SingleIn` annotations as the annotated class no longer have to be singletons
This commit is contained in:
Jorge Martin Espinosa 2025-08-22 08:59:06 +02:00 committed by GitHub
parent 3faaab407f
commit 8245ad8bc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 198 additions and 138 deletions

View file

@ -7,28 +7,22 @@
package io.element.android.libraries.preferences.impl.store
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
import io.element.android.libraries.matrix.api.tracing.LogLevel
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import io.element.android.libraries.preferences.api.store.PreferenceDataStoreFactory
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "elementx_preferences")
private val developerModeKey = booleanPreferencesKey("developerMode")
private val customElementCallBaseUrlKey = stringPreferencesKey("elementCallBaseUrl")
private val themeKey = stringPreferencesKey("theme")
@ -39,10 +33,10 @@ private val traceLogPacksKey = stringPreferencesKey("traceLogPacks")
@ContributesBinding(AppScope::class)
class DefaultAppPreferencesStore @Inject constructor(
@ApplicationContext context: Context,
private val buildMeta: BuildMeta,
preferenceDataStoreFactory: PreferenceDataStoreFactory,
) : AppPreferencesStore {
private val store = context.dataStore
private val store = preferenceDataStoreFactory.create("elementx_preferences")
override suspend fun setDeveloperModeEnabled(enabled: Boolean) {
store.edit { prefs ->

View file

@ -12,6 +12,7 @@ import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.androidutils.preferences.DefaultPreferencesCorruptionHandlerFactory
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.SingleIn
@ -27,7 +28,10 @@ class DefaultPreferencesDataStoreFactory @Inject constructor(
private val dataStoreHolders = ConcurrentHashMap<String, DataStoreHolder>()
private class DataStoreHolder(name: String) {
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = name)
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
name = name,
corruptionHandler = DefaultPreferencesCorruptionHandlerFactory.replaceWithEmpty(),
)
}
override fun create(name: String): DataStore<Preferences> {