providing a caching preferences abstraction to reading from an in memory value

This commit is contained in:
Adam Brown 2022-09-13 21:15:41 +01:00
parent e2f7b935d9
commit 31318037a7
10 changed files with 67 additions and 25 deletions

View File

@ -126,7 +126,7 @@ internal class AppModule(context: Application, logger: MatrixLogger) {
attachments
)
},
unsafeLazy { storeModule.value.preferences }
unsafeLazy { storeModule.value.cachingPreferences },
)
val featureModules = FeatureModules(

View File

@ -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())

View File

@ -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<Preferences>,
private val preferences: Lazy<CachedPreferences>,
) : ProvidableModule {
fun intentFactory() = intentFactory
private val themeStore by unsafeLazy { ThemeStore(preferences.value) }
fun themeStore() = themeStore
fun themeStore() = ThemeStore(preferences.value)
}

View File

@ -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()
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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()
}
}

View File

@ -0,0 +1,16 @@
package app.dapk.st.domain.preference
@Suppress("UNCHECKED_CAST")
class PropertyCache {
private val map = mutableMapOf<String, Any>()
fun <T> getValue(key: String): T? {
return map[key] as? T?
}
fun setValue(key: String, value: Any) {
map[key] = value
}
}

View File

@ -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()