Explorar el Código

fix: DataStore迁移后主题配置丢失导致composeEngine重置

postMigrationSync()在App启动时校验SP中的主题key,若缺失则从DataStore补回。
解决进入ReadBookScreen触发首次DS访问后,composeEngine等配置被重置的问题。
HapeLee hace 5 meses
padre
commit
4cc04b20d5

+ 5 - 0
app/src/main/java/io/legado/app/App.kt

@@ -44,6 +44,7 @@ import io.legado.app.help.DispatchersMonitor
 import io.legado.app.help.LifecycleHelp
 import io.legado.app.help.LifecycleHelp
 import io.legado.app.help.RuleBigDataHelp
 import io.legado.app.help.RuleBigDataHelp
 import io.legado.app.help.book.BookHelp
 import io.legado.app.help.book.BookHelp
+import io.legado.app.data.repository.SettingsRepository
 import io.legado.app.help.config.AppConfig
 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.config.ThemeConfigStore.applyDayNightInit
 import io.legado.app.help.config.ThemeConfigStore.applyDayNightInit
@@ -136,6 +137,10 @@ class App : Application(), ImageLoaderFactory {
             LogUtils.init(this@App)
             LogUtils.init(this@App)
             LogUtils.d("App", "onCreate")
             LogUtils.d("App", "onCreate")
             LogUtils.logDeviceInfo()
             LogUtils.logDeviceInfo()
+            // 确保 DataStore 迁移后 SP 中的主题配置值未丢失
+            kotlin.runCatching {
+                get<SettingsRepository>().postMigrationSync()
+            }
             //预下载Cronet so
             //预下载Cronet so
             Cronet.preDownload()
             Cronet.preDownload()
             createNotificationChannels()
             createNotificationChannels()

+ 43 - 0
app/src/main/java/io/legado/app/data/repository/SettingsRepository.kt

@@ -1,10 +1,13 @@
 package io.legado.app.data.repository
 package io.legado.app.data.repository
 
 
 import android.content.Context
 import android.content.Context
+import androidx.core.content.edit
 import androidx.datastore.core.DataStore
 import androidx.datastore.core.DataStore
 import androidx.datastore.preferences.SharedPreferencesMigration
 import androidx.datastore.preferences.SharedPreferencesMigration
 import androidx.datastore.preferences.core.*
 import androidx.datastore.preferences.core.*
 import androidx.datastore.preferences.preferencesDataStore
 import androidx.datastore.preferences.preferencesDataStore
+import io.legado.app.constant.PreferKey
+import io.legado.app.utils.defaultSharedPreferences
 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
@@ -14,6 +17,7 @@ import io.legado.app.utils.putPrefStringSet
 import io.legado.app.utils.removePref
 import io.legado.app.utils.removePref
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.map
 import java.io.IOException
 import java.io.IOException
 
 
@@ -149,6 +153,45 @@ class SettingsRepository(private val context: Context) {
         }
         }
     }
     }
 
 
+    /**
+     * DataStore 迁移后同步校验:确保 SP 中的主题配置值未被迁移过程丢失。
+     *
+     * SharedPreferencesMigration 在首次访问 DataStore 时运行,将 SP 值复制到 DataStore。
+     * 在某些场景下(进程被杀、ROM 行为等),迁移可能导致 SP 中的值丢失。
+     * 此方法从 DataStore 读取关键主题配置,如果 SP 中缺失则补写回去。
+     */
+    suspend fun postMigrationSync() {
+        val prefs = dataStore.data.first()
+        val sp = context.defaultSharedPreferences
+        val themeKeys = listOf(
+            PreferKey.composeEngine,
+            PreferKey.appTheme,
+            PreferKey.themeMode,
+            PreferKey.paletteStyle,
+            PreferKey.materialVersion,
+            PreferKey.customContrast,
+            PreferKey.customMode,
+        )
+        var needsWrite = false
+        val editor = mutableMapOf<String, String>()
+        for (key in themeKeys) {
+            if (!sp.contains(key)) {
+                val dsValue = prefs[stringPreferencesKey(key)]
+                if (dsValue != null) {
+                    editor[key] = dsValue
+                    needsWrite = true
+                }
+            }
+        }
+        if (needsWrite) {
+            sp.edit {
+                editor.forEach { (key, value) ->
+                    putString(key, value)
+                }
+            }
+        }
+    }
+
     // 移除配置
     // 移除配置
     suspend fun remove(key: String) {
     suspend fun remove(key: String) {
         dataStore.edit { preferences ->
         dataStore.edit { preferences ->