Jelajahi Sumber

[修复] 切换自定义主题不再需要重启

DynamicColors.applyToActivitiesIfAvailable 只是向 Application 注册一个
ActivityLifecycleCallbacks,它有两个问题:

1. 只对之后创建的 Activity 生效,当前 Activity 拿不到新配色,所以切换到
   自定义主题(12)后即使 recreate 也不变色,只能靠重启;
2. Material 没有提供注销接口,注册后终生存在。initTheme() 每创建一个
   Activity 就注册一次,callback 会不断堆积,切走后旧配色仍会作用于新
   建的 Activity。

改用 per-activity 的 applyToActivityIfAvailable(this, ...):initTheme()
在 super.onCreate() 之前执行,配色立即作用于当前 Activity,且不留全局
状态。这样 EventBus.RECREATE 就足以完成换肤,重启弹窗可以去掉。

注意 ThemeOverlay_WhiteBackground 会覆盖 colorSurface/colorBackground 等
属性,必须在动态取色之后应用,否则 accent 模式的白色背景会被动态配色盖掉。

顺带移除 CustomThemeScreen 里每次选取种子色都重新注册全局 callback 的逻辑,
改为发送 RECREATE。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5151561 3 bulan lalu
induk
melakukan
c97fff4bac

+ 8 - 7
app/src/main/java/io/legado/app/base/BaseActivity.kt

@@ -168,7 +168,7 @@ abstract class BaseActivity<VB : ViewBinding>(
     open fun initTheme() {
         when (getPrefString("app_theme", "0")) {
             "0" -> {
-                DynamicColors.applyToActivitiesIfAvailable(application)
+                DynamicColors.applyToActivityIfAvailable(this)
             }
             "1" -> setTheme(R.style.Theme_Base_GR)
             "2" -> setTheme(R.style.Theme_Base_Lemon)
@@ -182,9 +182,6 @@ abstract class BaseActivity<VB : ViewBinding>(
             "10" -> setTheme(R.style.Theme_Base_Phoebe)
             "11" -> setTheme(R.style.Theme_Base_Mujika)
             "12" -> {
-                if (AppConfig.customMode == "accent")
-                    setTheme(R.style.ThemeOverlay_WhiteBackground)
-
                 val colorImagePath = getPrefString(PreferKey.colorImage)
                 if (!colorImagePath.isNullOrBlank()) {
                     val file = File(colorImagePath)
@@ -200,18 +197,22 @@ abstract class BaseActivity<VB : ViewBinding>(
                                 .setContentBasedSource(scaledBitmap)
                                 .build()
 
-                            DynamicColors.applyToActivitiesIfAvailable(application, options)
+                            DynamicColors.applyToActivityIfAvailable(this, options)
                             bitmap.recycle()
                         }
                     }
                 }else{
-                    DynamicColors.applyToActivitiesIfAvailable(
-                        application,
+                    DynamicColors.applyToActivityIfAvailable(
+                        this,
                         DynamicColorsOptions.Builder()
                             .setContentBasedSource(application.primaryColor)
                             .build()
                     )
                 }
+
+                // 必须在动态取色之后应用,否则会被动态配色的 surface/background 覆盖
+                if (AppConfig.customMode == "accent")
+                    setTheme(R.style.ThemeOverlay_WhiteBackground)
             }
 
             "13" -> setTheme(R.style.AppTheme_Transparent)

+ 1 - 22
app/src/main/java/io/legado/app/lib/prefs/ThemeCardPreference.kt

@@ -4,8 +4,6 @@ import android.annotation.SuppressLint
 import android.content.Context
 import android.content.res.ColorStateList
 import android.graphics.Color
-import android.os.Handler
-import android.os.Looper
 import android.util.AttributeSet
 import android.view.ContextThemeWrapper
 import android.view.LayoutInflater
@@ -20,11 +18,9 @@ import com.google.android.material.card.MaterialCardView
 import io.legado.app.R
 import io.legado.app.constant.EventBus
 import io.legado.app.constant.PreferKey
-import io.legado.app.lib.dialogs.alert
 import io.legado.app.ui.config.themeConfig.ThemeConfig
 import io.legado.app.utils.getPrefString
 import io.legado.app.utils.postEvent
-import io.legado.app.utils.restart
 import io.legado.app.utils.toastOnUi
 import splitties.init.appCtx
 
@@ -98,29 +94,12 @@ class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(co
                             ThemeConfig.containerOpacity = 0
                         }
                     }
-                    val oldValue = currentValue
                     currentValue = value
                     persistString(value)
                     callChangeListener(value)
                     ThemeConfig.appTheme = value
                     notifyDataSetChanged()
-                    val isDynamicSwitch = (oldValue == "12" || value == "12")
-                    Handler(Looper.getMainLooper()).postDelayed({
-                        if (isDynamicSwitch) {
-                            context.alert(context.getString(R.string.restart_required_message)) {
-                                okButton {
-                                    Handler(Looper.getMainLooper()).postDelayed({
-                                        context.restart()
-                                    }, 100)
-                                }
-                                cancelButton {
-                                    context.toastOnUi(R.string.restart_later_message)
-                                }
-                            }
-                        } else {
-                            postEvent(EventBus.RECREATE, "")
-                        }
-                    }, 100)
+                    postEvent(EventBus.RECREATE, "")
                 }
             }
         }

+ 3 - 9
app/src/main/java/io/legado/app/ui/config/customTheme/CustomThemeScreen.kt

@@ -23,11 +23,9 @@ import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringArrayResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
-import com.google.android.material.color.DynamicColors
-import com.google.android.material.color.DynamicColorsOptions
 import io.legado.app.R
+import io.legado.app.constant.EventBus
 import io.legado.app.lib.theme.ThemeStore
-import io.legado.app.lib.theme.primaryColor
 import io.legado.app.ui.config.themeConfig.ThemeConfig
 import io.legado.app.ui.theme.adaptiveContentPadding
 import io.legado.app.ui.widget.components.AppScaffold
@@ -39,6 +37,7 @@ import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
 import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
 import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
+import io.legado.app.utils.postEvent
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -245,12 +244,7 @@ fun CustomThemeScreen(
                     ThemeStore.editTheme(context)
                         .primaryColor(color)
                         .apply()
-                    DynamicColors.applyToActivitiesIfAvailable(
-                        context.applicationContext as android.app.Application,
-                        DynamicColorsOptions.Builder()
-                            .setContentBasedSource(context.primaryColor)
-                            .build()
-                    )
+                    postEvent(EventBus.RECREATE, "")
                 }
             }
         )

+ 2 - 32
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt

@@ -3,8 +3,6 @@ package io.legado.app.ui.config.themeConfig
 import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Intent
-import android.os.Handler
-import android.os.Looper
 import androidx.activity.compose.rememberLauncherForActivityResult
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.compose.animation.AnimatedVisibility
@@ -85,7 +83,6 @@ import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.FontFolderState
 import io.legado.app.ui.widget.components.FontSelectSheet
 import io.legado.app.ui.widget.components.SplicedColumnGroup
-import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.button.series.SmallPlainButton
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
@@ -99,7 +96,6 @@ import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
 import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
 import io.legado.app.utils.postEvent
-import io.legado.app.utils.restart
 import io.legado.app.utils.takePersistablePermissionSafely
 import io.legado.app.utils.toastOnUi
 import org.koin.androidx.compose.koinViewModel
@@ -119,7 +115,6 @@ fun ThemeConfigScreen(
     var selectedThemeMode by remember { mutableStateOf(ThemeConfig.themeMode) }
     var selectedTheme by remember { mutableStateOf(ThemeConfig.appTheme) }
     var useMiuixMonet by remember { mutableStateOf(ThemeConfig.useMiuixMonet) }
-    var showRestartDialog by remember { mutableStateOf(false) }
     var showLauncherIconPicker by remember { mutableStateOf(false) }
     var showBorderColorPicker by remember { mutableStateOf(false) }
     var showNavIconSheet by remember { mutableStateOf(false) }
@@ -268,7 +263,7 @@ fun ThemeConfigScreen(
                                     selectedTheme = newTheme
                                     ThemeConfig.appTheme = newTheme
                                     if (oldTheme != newTheme) {
-                                        showRestartDialog = true
+                                        postEvent(EventBus.RECREATE, "")
                                     }
                                 }
                             )
@@ -310,15 +305,9 @@ fun ThemeConfigScreen(
                                         ThemeConfig.containerOpacity = 0
                                     }
                                 }
-                                val oldTheme = selectedTheme
                                 selectedTheme = theme
                                 ThemeConfig.appTheme = theme
-                                val isDynamicSwitch = (oldTheme == "12" || theme == "12")
-                                if (isDynamicSwitch) {
-                                    showRestartDialog = true
-                                } else {
-                                    postEvent(EventBus.RECREATE, "")
-                                }
+                                postEvent(EventBus.RECREATE, "")
                             }
                         )
                     }
@@ -819,25 +808,6 @@ fun ThemeConfigScreen(
     }
 
 
-    AppAlertDialog(
-        show = showRestartDialog,
-        onDismissRequest = { showRestartDialog = false },
-        title = stringResource(R.string.restart_required_message),
-        onConfirm = {
-            showRestartDialog = false
-            Handler(Looper.getMainLooper()).postDelayed({
-                context.restart()
-            }, 100)
-        },
-        confirmText = stringResource(R.string.ok),
-        onDismiss = {
-            showRestartDialog = false
-            context.toastOnUi(R.string.restart_later_message)
-        },
-        dismissText = stringResource(R.string.cancel)
-    )
-
-
     BackgroundImageManageSheet(
         isDarkTheme = manageKey,
         onDismissRequest = { manageKey = null }