fix: dataStore逻辑
This commit is contained in:
8 files changed
+83
-150
No files matched your search
@@ -1007,7 +1007,7 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
|||||||
var pureBlack
|
var pureBlack
|
||||||
get() = appCtx.getPrefBoolean(PreferKey.pureBlack, false)
|
get() = appCtx.getPrefBoolean(PreferKey.pureBlack, false)
|
||||||
set(value) {
|
set(value) {
|
||||||
appCtx.getPrefBoolean(PreferKey.pureBlack, value)
|
appCtx.putPrefBoolean(PreferKey.pureBlack, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasLightBg: Boolean
|
val hasLightBg: Boolean
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import com.google.android.material.card.MaterialCardView
|
|||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.constant.EventBus
|
import io.legado.app.constant.EventBus
|
||||||
import io.legado.app.constant.PreferKey
|
import io.legado.app.constant.PreferKey
|
||||||
import io.legado.app.help.config.AppConfig
|
|
||||||
import io.legado.app.lib.dialogs.alert
|
import io.legado.app.lib.dialogs.alert
|
||||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||||
import io.legado.app.utils.getPrefString
|
import io.legado.app.utils.getPrefString
|
||||||
@@ -90,7 +89,7 @@ class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(co
|
|||||||
context.toastOnUi(R.string.transparent_theme_alarm)
|
context.toastOnUi(R.string.transparent_theme_alarm)
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
} else {
|
} else {
|
||||||
AppConfig.containerOpacity = 0
|
ThemeConfig.containerOpacity = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val oldValue = currentValue
|
val oldValue = currentValue
|
||||||
|
|||||||
@@ -2587,7 +2587,6 @@ class ReadBookViewModel(
|
|||||||
else -> "0" // dark → follow system
|
else -> "0" // dark → follow system
|
||||||
}
|
}
|
||||||
ThemeConfig.themeMode = nextMode
|
ThemeConfig.themeMode = nextMode
|
||||||
AppConfig.themeMode = nextMode
|
|
||||||
_uiState.update { it.copy(styleConfig = buildStyleConfig()) }
|
_uiState.update { it.copy(styleConfig = buildStyleConfig()) }
|
||||||
_effects.tryEmit(ReadBookEffect.UpdateReadViewConfig(
|
_effects.tryEmit(ReadBookEffect.UpdateReadViewConfig(
|
||||||
setOf(
|
setOf(
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
package io.legado.app.ui.config
|
package io.legado.app.ui.config
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import io.legado.app.utils.defaultSharedPreferences
|
|
||||||
import io.legado.app.utils.getPrefBoolean
|
|
||||||
import io.legado.app.utils.getPrefFloat
|
|
||||||
import io.legado.app.utils.getPrefInt
|
|
||||||
import io.legado.app.utils.getPrefLong
|
|
||||||
import io.legado.app.utils.getPrefString
|
|
||||||
import io.legado.app.utils.putPrefBoolean
|
import io.legado.app.utils.putPrefBoolean
|
||||||
import io.legado.app.utils.putPrefFloat
|
import io.legado.app.utils.putPrefFloat
|
||||||
import io.legado.app.utils.putPrefInt
|
import io.legado.app.utils.putPrefInt
|
||||||
@@ -24,8 +17,10 @@ import io.legado.app.data.repository.dataStore
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
@@ -49,39 +44,41 @@ fun <T> prefDelegate(
|
|||||||
sync: Boolean = false,
|
sync: Boolean = false,
|
||||||
onValueChange: ((T) -> Unit)? = null
|
onValueChange: ((T) -> Unit)? = null
|
||||||
): PrefDelegate<T> {
|
): PrefDelegate<T> {
|
||||||
return object : PrefDelegate<T>, SharedPreferences.OnSharedPreferenceChangeListener, DefaultLifecycleObserver {
|
return object : PrefDelegate<T>, DefaultLifecycleObserver {
|
||||||
private var _value: MutableState<T> = mutableStateOf(readInitialValue())
|
private var _value: MutableState<T> = mutableStateOf(defaultValue)
|
||||||
override val state: State<T> get() = _value
|
override val state: State<T> get() = _value
|
||||||
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
private var dsObserverJob: Job? = null
|
private var dsObserverJob: Job? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (lifecycleOwner != null) {
|
// 从 DataStore 读取初始值(DS 为唯一读取源)
|
||||||
lifecycleOwner.lifecycle.addObserver(this)
|
scope.launch {
|
||||||
} else {
|
val dsValue = readFromDs()
|
||||||
appCtx.defaultSharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
if (dsValue != null) {
|
||||||
|
_value.value = dsValue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 观察 DataStore,以 DS 为读取权威源
|
// 观察 DataStore 变化,用于跨实例同步
|
||||||
dsObserverJob = CoroutineScope(Dispatchers.IO).launch {
|
dsObserverJob = scope.launch {
|
||||||
appCtx.dataStore.data
|
appCtx.dataStore.data
|
||||||
.catch { if (it is IOException) emit(emptyPreferences()) else throw it }
|
.catch { if (it is IOException) emit(emptyPreferences()) else throw it }
|
||||||
.map { prefs ->
|
.map { prefs ->
|
||||||
// 安全读取 String 值,用于类型回退(类型不匹配时返回 null)
|
|
||||||
val strVal = runCatching { prefs[stringPreferencesKey(key)] }.getOrNull()
|
val strVal = runCatching { prefs[stringPreferencesKey(key)] }.getOrNull()
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
when {
|
when {
|
||||||
defaultValue is String || defaultValue == null ->
|
defaultValue is String || defaultValue == null ->
|
||||||
strVal as T?
|
strVal as T?
|
||||||
defaultValue is Int ->
|
defaultValue is Int ->
|
||||||
(prefs[intPreferencesKey(key)]
|
(runCatching { prefs[intPreferencesKey(key)] }.getOrNull()
|
||||||
?: strVal?.toIntOrNull()) as T?
|
?: strVal?.toIntOrNull()) as T?
|
||||||
defaultValue is Boolean ->
|
defaultValue is Boolean ->
|
||||||
(prefs[booleanPreferencesKey(key)]
|
(runCatching { prefs[booleanPreferencesKey(key)] }.getOrNull()
|
||||||
?: strVal?.toBooleanStrictOrNull()) as T?
|
?: strVal?.toBooleanStrictOrNull()) as T?
|
||||||
defaultValue is Long ->
|
defaultValue is Long ->
|
||||||
(prefs[longPreferencesKey(key)]
|
(runCatching { prefs[longPreferencesKey(key)] }.getOrNull()
|
||||||
?: strVal?.toLongOrNull()) as T?
|
?: strVal?.toLongOrNull()) as T?
|
||||||
defaultValue is Float ->
|
defaultValue is Float ->
|
||||||
(prefs[floatPreferencesKey(key)]
|
(runCatching { prefs[floatPreferencesKey(key)] }.getOrNull()
|
||||||
?: strVal?.toFloatOrNull()) as T?
|
?: strVal?.toFloatOrNull()) as T?
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -94,10 +91,10 @@ fun <T> prefDelegate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// 注册生命周期观察者(如果有)
|
||||||
|
if (lifecycleOwner != null) {
|
||||||
override fun onCreate(owner: LifecycleOwner) {
|
lifecycleOwner.lifecycle.addObserver(this)
|
||||||
appCtx.defaultSharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy(owner: LifecycleOwner) {
|
override fun onDestroy(owner: LifecycleOwner) {
|
||||||
@@ -105,33 +102,17 @@ fun <T> prefDelegate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
appCtx.defaultSharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
|
||||||
dsObserverJob?.cancel()
|
dsObserverJob?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private fun readInitialValue(): T {
|
|
||||||
val prefs = appCtx.defaultSharedPreferences
|
|
||||||
return when {
|
|
||||||
defaultValue is String -> appCtx.getPrefString(key, defaultValue) as T
|
|
||||||
defaultValue == null && prefs.contains(key) -> {
|
|
||||||
appCtx.getPrefString(key, null) as T
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultValue is Int -> appCtx.getPrefInt(key, defaultValue) as T
|
|
||||||
defaultValue is Boolean -> appCtx.getPrefBoolean(key, defaultValue) as T
|
|
||||||
defaultValue is Long -> appCtx.getPrefLong(key, defaultValue) as T
|
|
||||||
defaultValue is Float -> appCtx.getPrefFloat(key, defaultValue) as T
|
|
||||||
else -> defaultValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
return _value.value
|
return _value.value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
if (_value.value != value) {
|
if (_value.value != value) {
|
||||||
|
_value.value = value
|
||||||
|
// 同步写入 SP(向后兼容:AppConfig/MainViewModel 等仍直接读 SP)
|
||||||
when (value) {
|
when (value) {
|
||||||
is String? -> if (sync) appCtx.putPrefStringSync(key, value) else appCtx.putPrefString(key, value)
|
is String? -> if (sync) appCtx.putPrefStringSync(key, value) else appCtx.putPrefString(key, value)
|
||||||
is Int -> appCtx.putPrefInt(key, value)
|
is Int -> appCtx.putPrefInt(key, value)
|
||||||
@@ -139,8 +120,8 @@ fun <T> prefDelegate(
|
|||||||
is Long -> appCtx.putPrefLong(key, value)
|
is Long -> appCtx.putPrefLong(key, value)
|
||||||
is Float -> appCtx.putPrefFloat(key, value)
|
is Float -> appCtx.putPrefFloat(key, value)
|
||||||
}
|
}
|
||||||
// 同步写入 DataStore,保持 SP/DS 一致
|
// 同步写入 DataStore(权威存储),确保持久化后再返回
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
runBlocking(Dispatchers.IO) {
|
||||||
when (value) {
|
when (value) {
|
||||||
is String? -> DsSync.putString(key, value)
|
is String? -> DsSync.putString(key, value)
|
||||||
is Int -> DsSync.putInt(key, value)
|
is Int -> DsSync.putInt(key, value)
|
||||||
@@ -149,18 +130,42 @@ fun <T> prefDelegate(
|
|||||||
is Float -> DsSync.putFloat(key, value)
|
is Float -> DsSync.putFloat(key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_value.value = value
|
|
||||||
onValueChange?.invoke(value)
|
onValueChange?.invoke(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, changedKey: String?) {
|
/**
|
||||||
if (changedKey == key) {
|
* 从 DataStore 读取当前值。
|
||||||
val newValue = readInitialValue()
|
* DS 为唯一读取源,类型不匹配时安全回退到 String 解析。
|
||||||
if (_value.value != newValue) {
|
*/
|
||||||
_value.value = newValue
|
@Suppress("UNCHECKED_CAST")
|
||||||
onValueChange?.invoke(newValue)
|
private suspend fun readFromDs(): T? {
|
||||||
}
|
return try {
|
||||||
|
appCtx.dataStore.data
|
||||||
|
.catch { if (it is IOException) emit(emptyPreferences()) else throw it }
|
||||||
|
.map { prefs ->
|
||||||
|
val strVal = runCatching { prefs[stringPreferencesKey(key)] }.getOrNull()
|
||||||
|
when {
|
||||||
|
defaultValue is String || defaultValue == null ->
|
||||||
|
strVal as T?
|
||||||
|
defaultValue is Int ->
|
||||||
|
(runCatching { prefs[intPreferencesKey(key)] }.getOrNull()
|
||||||
|
?: strVal?.toIntOrNull()) as T?
|
||||||
|
defaultValue is Boolean ->
|
||||||
|
(runCatching { prefs[booleanPreferencesKey(key)] }.getOrNull()
|
||||||
|
?: strVal?.toBooleanStrictOrNull()) as T?
|
||||||
|
defaultValue is Long ->
|
||||||
|
(runCatching { prefs[longPreferencesKey(key)] }.getOrNull()
|
||||||
|
?: strVal?.toLongOrNull()) as T?
|
||||||
|
defaultValue is Float ->
|
||||||
|
(runCatching { prefs[floatPreferencesKey(key)] }.getOrNull()
|
||||||
|
?: strVal?.toFloatOrNull()) as T?
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.first()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,4 +180,4 @@ fun <T> prefStateDelegate(
|
|||||||
): PrefStateDelegate<T> {
|
): PrefStateDelegate<T> {
|
||||||
val delegate = prefDelegate(key, defaultValue, lifecycleOwner, sync, onValueChange)
|
val delegate = prefDelegate(key, defaultValue, lifecycleOwner, sync, onValueChange)
|
||||||
return PrefStateDelegate(delegate)
|
return PrefStateDelegate(delegate)
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,6 @@ import io.legado.app.base.AppContextWrapper
|
|||||||
import io.legado.app.constant.EventBus
|
import io.legado.app.constant.EventBus
|
||||||
import io.legado.app.constant.PreferKey
|
import io.legado.app.constant.PreferKey
|
||||||
import io.legado.app.help.LauncherIconHelp
|
import io.legado.app.help.LauncherIconHelp
|
||||||
import io.legado.app.help.config.AppConfig
|
|
||||||
import io.legado.app.help.config.ThemeConfigStore
|
import io.legado.app.help.config.ThemeConfigStore
|
||||||
import io.legado.app.help.loadFontFiles
|
import io.legado.app.help.loadFontFiles
|
||||||
import io.legado.app.ui.config.labConfig.LabConfig
|
import io.legado.app.ui.config.labConfig.LabConfig
|
||||||
@@ -311,7 +310,7 @@ fun ThemeConfigScreen(
|
|||||||
context.toastOnUi(R.string.transparent_theme_alarm)
|
context.toastOnUi(R.string.transparent_theme_alarm)
|
||||||
return@ThemeColorSelector
|
return@ThemeColorSelector
|
||||||
} else {
|
} else {
|
||||||
AppConfig.containerOpacity = 0
|
ThemeConfig.containerOpacity = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val oldTheme = selectedTheme
|
val oldTheme = selectedTheme
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
package io.legado.app.ui.main
|
package io.legado.app.ui.main
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import io.legado.app.base.BaseViewModel
|
import io.legado.app.base.BaseViewModel
|
||||||
import io.legado.app.constant.EventBus
|
import io.legado.app.constant.EventBus
|
||||||
import io.legado.app.constant.PreferKey
|
|
||||||
import io.legado.app.domain.usecase.AppStartupMaintenanceUseCase
|
import io.legado.app.domain.usecase.AppStartupMaintenanceUseCase
|
||||||
import io.legado.app.domain.usecase.WebDavBackupUseCase
|
import io.legado.app.domain.usecase.WebDavBackupUseCase
|
||||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||||
import io.legado.app.ui.main.my.PrefClickEvent
|
import io.legado.app.ui.main.my.PrefClickEvent
|
||||||
import io.legado.app.utils.defaultSharedPreferences
|
|
||||||
import io.legado.app.utils.eventBus.FlowEventBus
|
import io.legado.app.utils.eventBus.FlowEventBus
|
||||||
import io.legado.app.utils.getPrefBoolean
|
|
||||||
import io.legado.app.utils.getPrefString
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
@@ -21,6 +18,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainViewModel(
|
class MainViewModel(
|
||||||
application: Application,
|
application: Application,
|
||||||
@@ -28,40 +26,25 @@ class MainViewModel(
|
|||||||
private val webDavBackupUseCase: WebDavBackupUseCase
|
private val webDavBackupUseCase: WebDavBackupUseCase
|
||||||
) : BaseViewModel(application) {
|
) : BaseViewModel(application) {
|
||||||
|
|
||||||
private val prefs = context.defaultSharedPreferences
|
|
||||||
private val mainPreferenceKeys = setOf(
|
|
||||||
PreferKey.showDiscovery,
|
|
||||||
PreferKey.showHome,
|
|
||||||
PreferKey.showRss,
|
|
||||||
PreferKey.showBottomView,
|
|
||||||
PreferKey.useFloatingBottomBar,
|
|
||||||
PreferKey.useFloatingBottomBarLiquidGlass,
|
|
||||||
PreferKey.defaultHomePage,
|
|
||||||
PreferKey.labelVisibilityMode,
|
|
||||||
NAV_EXTENDED_KEY
|
|
||||||
)
|
|
||||||
private val preferenceListener =
|
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
|
||||||
if (key in mainPreferenceKeys) {
|
|
||||||
_uiState.value = readMainUiState()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _uiState = MutableStateFlow(readMainUiState())
|
private val _uiState = MutableStateFlow(readMainUiState())
|
||||||
val uiState = _uiState.asStateFlow()
|
val uiState = _uiState.asStateFlow()
|
||||||
private val _effects = MutableSharedFlow<MainEffect>(extraBufferCapacity = 8)
|
private val _effects = MutableSharedFlow<MainEffect>(extraBufferCapacity = 8)
|
||||||
val effects = _effects.asSharedFlow()
|
val effects = _effects.asSharedFlow()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
prefs.registerOnSharedPreferenceChangeListener(preferenceListener)
|
// 通过 snapshotFlow 直接观察 ThemeConfig 的 Compose State,全链路走 DS
|
||||||
|
viewModelScope.launch {
|
||||||
|
snapshotFlow {
|
||||||
|
readMainUiState()
|
||||||
|
}.collect { newState ->
|
||||||
|
if (_uiState.value != newState) {
|
||||||
|
_uiState.value = newState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
deleteNotShelfBook()
|
deleteNotShelfBook()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
|
||||||
prefs.unregisterOnSharedPreferenceChangeListener(preferenceListener)
|
|
||||||
super.onCleared()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun upAllBookToc() {
|
fun upAllBookToc() {
|
||||||
FlowEventBus.post(EventBus.UP_ALL_BOOK_TOC, Unit)
|
FlowEventBus.post(EventBus.UP_ALL_BOOK_TOC, Unit)
|
||||||
}
|
}
|
||||||
@@ -149,31 +132,22 @@ data class MainUiState(
|
|||||||
val navExtended: Boolean = false
|
val navExtended: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
private const val NAV_EXTENDED_KEY = "navExtended"
|
|
||||||
|
|
||||||
private fun MainViewModel.readMainUiState(): MainUiState {
|
private fun MainViewModel.readMainUiState(): MainUiState {
|
||||||
val showDiscovery = context.getPrefBoolean(PreferKey.showDiscovery, true)
|
|
||||||
val showHome = context.getPrefBoolean(PreferKey.showHome, true)
|
|
||||||
val showRss = context.getPrefBoolean(PreferKey.showRss, true)
|
|
||||||
val destinations = MainDestination.mainDestinations.filter {
|
val destinations = MainDestination.mainDestinations.filter {
|
||||||
when (it) {
|
when (it) {
|
||||||
MainDestination.Explore -> showDiscovery
|
MainDestination.Explore -> ThemeConfig.showDiscovery
|
||||||
MainDestination.Home -> showHome
|
MainDestination.Home -> ThemeConfig.showHome
|
||||||
MainDestination.Rss -> showRss
|
MainDestination.Rss -> ThemeConfig.showRss
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
}.toImmutableList()
|
}.toImmutableList()
|
||||||
return MainUiState(
|
return MainUiState(
|
||||||
destinations = destinations,
|
destinations = destinations,
|
||||||
defaultHomePage = context.getPrefString(PreferKey.defaultHomePage, "bookshelf")
|
defaultHomePage = ThemeConfig.defaultHomePage,
|
||||||
?: "bookshelf",
|
showBottomView = ThemeConfig.showBottomView,
|
||||||
showBottomView = context.getPrefBoolean(PreferKey.showBottomView, true),
|
useFloatingBottomBar = ThemeConfig.useFloatingBottomBar,
|
||||||
useFloatingBottomBar = context.getPrefBoolean(PreferKey.useFloatingBottomBar, false),
|
useFloatingBottomBarLiquidGlass = ThemeConfig.useFloatingBottomBarLiquidGlass,
|
||||||
useFloatingBottomBarLiquidGlass = context.getPrefBoolean(
|
labelVisibilityMode = ThemeConfig.labelVisibilityMode,
|
||||||
PreferKey.useFloatingBottomBarLiquidGlass,
|
navExtended = ThemeConfig.navExtended
|
||||||
false
|
|
||||||
),
|
|
||||||
labelVisibilityMode = context.getPrefString(PreferKey.labelVisibilityMode, "auto") ?: "auto",
|
|
||||||
navExtended = context.getPrefBoolean(NAV_EXTENDED_KEY, false)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,6 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.datastore.preferences.preferencesDataStore
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
|
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
@@ -464,8 +463,6 @@ val Context.channel: String
|
|||||||
val Context.isDebuggable: Boolean
|
val Context.isDebuggable: Boolean
|
||||||
get() = applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0
|
get() = applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0
|
||||||
|
|
||||||
val Context.dataStore by preferencesDataStore(name = "settings")
|
|
||||||
|
|
||||||
val Context.bookshelfLayoutMode: Int
|
val Context.bookshelfLayoutMode: Int
|
||||||
get() = if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
get() = if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
AppConfig.bookshelfLayoutModeLandscape
|
AppConfig.bookshelfLayoutModeLandscape
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
package io.legado.app.utils
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
|
||||||
import androidx.datastore.preferences.core.edit
|
|
||||||
import androidx.datastore.preferences.core.floatPreferencesKey
|
|
||||||
import androidx.datastore.preferences.core.intPreferencesKey
|
|
||||||
import androidx.datastore.preferences.core.longPreferencesKey
|
|
||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
object DataStoreUtil {
|
|
||||||
|
|
||||||
suspend fun <T> save(context: Context, key: String, value: T) {
|
|
||||||
context.dataStore.edit { preferences ->
|
|
||||||
when (value) {
|
|
||||||
is String -> preferences[stringPreferencesKey(key)] = value
|
|
||||||
is Int -> preferences[intPreferencesKey(key)] = value
|
|
||||||
is Boolean -> preferences[booleanPreferencesKey(key)] = value
|
|
||||||
is Float -> preferences[floatPreferencesKey(key)] = value
|
|
||||||
is Long -> preferences[longPreferencesKey(key)] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
suspend fun <T> read(context: Context, key: String, defaultValue: T): T {
|
|
||||||
return context.dataStore.data.map { preferences ->
|
|
||||||
when (defaultValue) {
|
|
||||||
is String -> preferences[stringPreferencesKey(key)] ?: defaultValue
|
|
||||||
is Int -> preferences[intPreferencesKey(key)] ?: defaultValue
|
|
||||||
is Boolean -> preferences[booleanPreferencesKey(key)] ?: defaultValue
|
|
||||||
is Float -> preferences[floatPreferencesKey(key)] ?: defaultValue
|
|
||||||
is Long -> preferences[longPreferencesKey(key)] ?: defaultValue
|
|
||||||
else -> defaultValue
|
|
||||||
} as T
|
|
||||||
}.first()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user