From 31318037a75785e2ba95e7660e13fcef234457e2 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 13 Sep 2022 21:15:41 +0100 Subject: [PATCH] providing a caching preferences abstraction to reading from an in memory value --- .../kotlin/app/dapk/st/graph/AppModule.kt | 2 +- .../kotlin/app/dapk/st/core/Preferences.kt | 2 ++ .../app/dapk/st/core/CoreAndroidModule.kt | 7 ++--- .../kotlin/app/dapk/st/core/DapkActivity.kt | 11 +++++--- .../kotlin/app/dapk/st/core/ThemeStore.kt | 17 +++--------- .../kotlin/app/dapk/st/domain/StoreModule.kt | 6 +++++ .../st/domain/eventlog/EventLogPersistence.kt | 3 ++- .../domain/preference/CachingPreferences.kt | 26 +++++++++++++++++++ .../st/domain/preference/PropertyCache.kt | 16 ++++++++++++ .../dapk/st/settings/SettingsItemFactory.kt | 2 +- 10 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 domains/store/src/main/kotlin/app/dapk/st/domain/preference/CachingPreferences.kt create mode 100644 domains/store/src/main/kotlin/app/dapk/st/domain/preference/PropertyCache.kt diff --git a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt index 4dc6890..8f79116 100644 --- a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt +++ b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt @@ -126,7 +126,7 @@ internal class AppModule(context: Application, logger: MatrixLogger) { attachments ) }, - unsafeLazy { storeModule.value.preferences } + unsafeLazy { storeModule.value.cachingPreferences }, ) val featureModules = FeatureModules( diff --git a/core/src/main/kotlin/app/dapk/st/core/Preferences.kt b/core/src/main/kotlin/app/dapk/st/core/Preferences.kt index 4d1cc3f..6a27901 100644 --- a/core/src/main/kotlin/app/dapk/st/core/Preferences.kt +++ b/core/src/main/kotlin/app/dapk/st/core/Preferences.kt @@ -8,5 +8,7 @@ interface Preferences { suspend fun remove(key: String) } +interface CachedPreferences : Preferences + suspend fun Preferences.readBoolean(key: String) = this.readString(key)?.toBooleanStrict() suspend fun Preferences.store(key: String, value: Boolean) = this.store(key, value.toString()) \ No newline at end of file diff --git a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/CoreAndroidModule.kt b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/CoreAndroidModule.kt index b84e2c7..f9bc464 100644 --- a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/CoreAndroidModule.kt +++ b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/CoreAndroidModule.kt @@ -1,17 +1,14 @@ package app.dapk.st.core -import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.navigator.IntentFactory class CoreAndroidModule( private val intentFactory: IntentFactory, - private val preferences: Lazy, + private val preferences: Lazy, ) : ProvidableModule { fun intentFactory() = intentFactory - private val themeStore by unsafeLazy { ThemeStore(preferences.value) } - - fun themeStore() = themeStore + fun themeStore() = ThemeStore(preferences.value) } \ No newline at end of file diff --git a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/DapkActivity.kt b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/DapkActivity.kt index fbcf0ed..4a9cc24 100644 --- a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/DapkActivity.kt +++ b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/DapkActivity.kt @@ -8,10 +8,13 @@ import androidx.activity.ComponentActivity import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect +import androidx.lifecycle.lifecycleScope import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.design.components.SmallTalkTheme import app.dapk.st.design.components.ThemeConfig import app.dapk.st.navigator.navigator +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.resume import androidx.activity.compose.setContent as _setContent @@ -29,7 +32,7 @@ abstract class DapkActivity : ComponentActivity(), EffectScope { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - this.themeConfig = ThemeConfig(themeStore.isMaterialYouEnabled()) + this.themeConfig = runBlocking { ThemeConfig(themeStore.isMaterialYouEnabled()) } window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); @@ -45,8 +48,10 @@ abstract class DapkActivity : ComponentActivity(), EffectScope { override fun onResume() { super.onResume() - if (themeConfig.useDynamicTheme != themeStore.isMaterialYouEnabled()) { - recreate() + lifecycleScope.launch { + if (themeConfig.useDynamicTheme != themeStore.isMaterialYouEnabled()) { + recreate() + } } } diff --git a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/ThemeStore.kt b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/ThemeStore.kt index ff3d2f5..cc46cac 100644 --- a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/ThemeStore.kt +++ b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/ThemeStore.kt @@ -1,26 +1,15 @@ package app.dapk.st.core -import kotlinx.coroutines.runBlocking - private const val KEY_MATERIAL_YOU_ENABLED = "material_you_enabled" class ThemeStore( - private val preferences: Preferences + private val preferences: CachedPreferences ) { - private var _isMaterialYouEnabled: Boolean? = null - - fun isMaterialYouEnabled() = _isMaterialYouEnabled ?: blockingInitialRead() - - private fun blockingInitialRead(): Boolean { - return runBlocking { - (preferences.readBoolean(KEY_MATERIAL_YOU_ENABLED) ?: false).also { _isMaterialYouEnabled = it } - } - } + suspend fun isMaterialYouEnabled() = preferences.readBoolean(KEY_MATERIAL_YOU_ENABLED) ?: false.also { storeMaterialYouEnabled(false) } suspend fun storeMaterialYouEnabled(isEnabled: Boolean) { - _isMaterialYouEnabled = isEnabled preferences.store(KEY_MATERIAL_YOU_ENABLED, isEnabled) } -} \ No newline at end of file +} diff --git a/domains/store/src/main/kotlin/app/dapk/st/domain/StoreModule.kt b/domains/store/src/main/kotlin/app/dapk/st/domain/StoreModule.kt index 874b8f5..94f978e 100644 --- a/domains/store/src/main/kotlin/app/dapk/st/domain/StoreModule.kt +++ b/domains/store/src/main/kotlin/app/dapk/st/domain/StoreModule.kt @@ -7,6 +7,8 @@ import app.dapk.st.core.extensions.ErrorTracker import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.domain.eventlog.EventLogPersistence import app.dapk.st.domain.localecho.LocalEchoPersistence +import app.dapk.st.domain.preference.CachingPreferences +import app.dapk.st.domain.preference.PropertyCache import app.dapk.st.domain.profile.ProfilePersistence import app.dapk.st.domain.push.PushTokenRegistrarPreferences import app.dapk.st.domain.sync.OverviewPersistence @@ -36,6 +38,9 @@ class StoreModule( fun filterStore(): FilterStore = FilterPreferences(preferences) val localEchoStore: LocalEchoStore by unsafeLazy { LocalEchoPersistence(errorTracker, database) } + private val cache = PropertyCache() + val cachingPreferences = CachingPreferences(cache, preferences) + fun pushStore() = PushTokenRegistrarPreferences(preferences) fun applicationStore() = ApplicationPreferences(preferences) @@ -60,4 +65,5 @@ class StoreModule( fun memberStore(): MemberStore { return MemberPersistence(database, coroutineDispatchers) } + } diff --git a/domains/store/src/main/kotlin/app/dapk/st/domain/eventlog/EventLogPersistence.kt b/domains/store/src/main/kotlin/app/dapk/st/domain/eventlog/EventLogPersistence.kt index ff65dca..4cd41ec 100644 --- a/domains/store/src/main/kotlin/app/dapk/st/domain/eventlog/EventLogPersistence.kt +++ b/domains/store/src/main/kotlin/app/dapk/st/domain/eventlog/EventLogPersistence.kt @@ -1,8 +1,8 @@ package app.dapk.st.domain.eventlog +import app.dapk.db.DapkDb import app.dapk.st.core.CoroutineDispatchers import app.dapk.st.core.withIoContext -import app.dapk.db.DapkDb import com.squareup.sqldelight.runtime.coroutines.asFlow import com.squareup.sqldelight.runtime.coroutines.mapToList import kotlinx.coroutines.flow.Flow @@ -42,6 +42,7 @@ class EventLogPersistence( ) } } + else -> database.eventLoggerQueries.selectLatestByLogFiltered(logKey, filter) .asFlow() .mapToList(context = coroutineDispatchers.io) diff --git a/domains/store/src/main/kotlin/app/dapk/st/domain/preference/CachingPreferences.kt b/domains/store/src/main/kotlin/app/dapk/st/domain/preference/CachingPreferences.kt new file mode 100644 index 0000000..0b42a40 --- /dev/null +++ b/domains/store/src/main/kotlin/app/dapk/st/domain/preference/CachingPreferences.kt @@ -0,0 +1,26 @@ +package app.dapk.st.domain.preference + +import app.dapk.st.core.CachedPreferences +import app.dapk.st.core.Preferences + +class CachingPreferences(private val cache: PropertyCache, private val preferences: Preferences) : CachedPreferences { + + override suspend fun store(key: String, value: String) { + cache.setValue(key, value) + preferences.store(key, value) + } + + override suspend fun readString(key: String): String? { + return cache.getValue(key) ?: preferences.readString(key)?.also { + cache.setValue(key, it) + } + } + + override suspend fun remove(key: String) { + preferences.remove(key) + } + + override suspend fun clear() { + preferences.clear() + } +} \ No newline at end of file diff --git a/domains/store/src/main/kotlin/app/dapk/st/domain/preference/PropertyCache.kt b/domains/store/src/main/kotlin/app/dapk/st/domain/preference/PropertyCache.kt new file mode 100644 index 0000000..41adfda --- /dev/null +++ b/domains/store/src/main/kotlin/app/dapk/st/domain/preference/PropertyCache.kt @@ -0,0 +1,16 @@ +package app.dapk.st.domain.preference + +@Suppress("UNCHECKED_CAST") +class PropertyCache { + + private val map = mutableMapOf() + + fun getValue(key: String): T? { + return map[key] as? T? + } + + fun setValue(key: String, value: Any) { + map[key] = value + } + +} \ No newline at end of file diff --git a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsItemFactory.kt b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsItemFactory.kt index a36e2f1..0a87f3d 100644 --- a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsItemFactory.kt +++ b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsItemFactory.kt @@ -19,7 +19,7 @@ internal class SettingsItemFactory( SettingItem.Text(SettingItem.Id.PushProvider, "Push provider", pushTokenRegistrars.currentSelection().id) ) - private fun theme() = listOfNotNull( + private suspend fun theme() = listOfNotNull( SettingItem.Header("Theme"), SettingItem.Toggle(SettingItem.Id.ToggleDynamicTheme, "Enable Material You", state = themeStore.isMaterialYouEnabled()).takeIf { deviceMeta.isAtLeastS()