Преглед изворни кода

fix: 修复自定义主题切换并区分日夜配色

HapeLee пре 4 месеци
родитељ
комит
1e695d06f1

+ 6 - 0
app/src/main/java/io/legado/app/constant/PreferKey.kt

@@ -213,6 +213,12 @@ object PreferKey {
     const val secondaryTextColor = "colorMD3OnPrimaryContainer"
     const val themeBackgroundColor = "colorMD3Background"
     const val labelContainerColor = "colorMD3SurfaceContainerLow"
+    const val themeColorNight = "colorMD3PrimaryNight"
+    const val secondaryThemeColorNight = "colorMD3SecondaryNight"
+    const val primaryTextColorNight = "colorMD3OnSurfaceNight"
+    const val secondaryTextColorNight = "colorMD3OnPrimaryContainerNight"
+    const val themeBackgroundColorNight = "colorMD3BackgroundNight"
+    const val labelContainerColorNight = "colorMD3SurfaceContainerLowNight"
     // 中间单线间隔设置
     const val enableItemDivider = "enableItemDivider"
     const val itemDividerWidth = "itemDividerWidth"

+ 18 - 0
app/src/main/java/io/legado/app/help/config/ThemeImportExport.kt

@@ -146,6 +146,12 @@ object ThemeImportExport {
             secondaryTextColor = ThemeConfig.secondaryTextColor,
             themeBackgroundColor = ThemeConfig.themeBackgroundColor,
             labelContainerColor = ThemeConfig.labelContainerColor,
+            themeColorNight = ThemeConfig.themeColorNight,
+            secondaryThemeColorNight = ThemeConfig.secondaryThemeColorNight,
+            primaryTextColorNight = ThemeConfig.primaryTextColorNight,
+            secondaryTextColorNight = ThemeConfig.secondaryTextColorNight,
+            themeBackgroundColorNight = ThemeConfig.themeBackgroundColorNight,
+            labelContainerColorNight = ThemeConfig.labelContainerColorNight,
             bookInfoInputColor = ThemeConfig.bookInfoInputColor,
 
             // 容器设置
@@ -317,6 +323,12 @@ object ThemeImportExport {
         ThemeConfig.secondaryTextColor = data.secondaryTextColor
         ThemeConfig.themeBackgroundColor = data.themeBackgroundColor
         ThemeConfig.labelContainerColor = data.labelContainerColor
+        ThemeConfig.themeColorNight = data.themeColorNight
+        ThemeConfig.secondaryThemeColorNight = data.secondaryThemeColorNight
+        ThemeConfig.primaryTextColorNight = data.primaryTextColorNight
+        ThemeConfig.secondaryTextColorNight = data.secondaryTextColorNight
+        ThemeConfig.themeBackgroundColorNight = data.themeBackgroundColorNight
+        ThemeConfig.labelContainerColorNight = data.labelContainerColorNight
         ThemeConfig.bookInfoInputColor = data.bookInfoInputColor
 
         // 容器设置
@@ -556,6 +568,12 @@ data class ThemeExportData(
     val secondaryTextColor: Int = 0,
     val themeBackgroundColor: Int = 0,
     val labelContainerColor: Int = 0,
+    val themeColorNight: Int = 0,
+    val secondaryThemeColorNight: Int = 0,
+    val primaryTextColorNight: Int = 0,
+    val secondaryTextColorNight: Int = 0,
+    val themeBackgroundColorNight: Int = 0,
+    val labelContainerColorNight: Int = 0,
     val bookInfoInputColor: Int = 0,
 
     // 容器设置

+ 8 - 2
app/src/main/java/io/legado/app/help/storage/BackupConfig.kt

@@ -91,6 +91,8 @@ object BackupConfig {
         PreferKey.bgImageNBlurring,
         PreferKey.themeColor,
         PreferKey.secondaryThemeColor,
+        PreferKey.themeColorNight,
+        PreferKey.secondaryThemeColorNight,
         PreferKey.paletteStyle,
         PreferKey.materialVersion,
         PreferKey.composeEngine,
@@ -116,7 +118,11 @@ object BackupConfig {
         PreferKey.primaryTextColor,
         PreferKey.secondaryTextColor,
         PreferKey.themeBackgroundColor,
-        PreferKey.labelContainerColor
+        PreferKey.labelContainerColor,
+        PreferKey.primaryTextColorNight,
+        PreferKey.secondaryTextColorNight,
+        PreferKey.themeBackgroundColorNight,
+        PreferKey.labelContainerColorNight
     )
 
     private val coverPrefKeys = arrayOf(
@@ -165,4 +171,4 @@ object BackupConfig {
         FileUtils.createFileIfNotExist(ignoreConfigPath).writeText(json)
     }
 
-}
+}

+ 102 - 140
app/src/main/java/io/legado/app/ui/config/customTheme/CustomThemeScreen.kt

@@ -59,6 +59,12 @@ fun CustomThemeScreen(
     val secondaryTextColor = ThemeConfig.secondaryTextColor
     val themeBackgroundColor = ThemeConfig.themeBackgroundColor
     val labelContainerColor = ThemeConfig.labelContainerColor
+    val themeColorNight = ThemeConfig.themeColorNight
+    val secondaryThemeColorNight = ThemeConfig.secondaryThemeColorNight
+    val primaryTextColorNight = ThemeConfig.primaryTextColorNight
+    val secondaryTextColorNight = ThemeConfig.secondaryTextColorNight
+    val themeBackgroundColorNight = ThemeConfig.themeBackgroundColorNight
+    val labelContainerColorNight = ThemeConfig.labelContainerColorNight
 
     val primaryColor = MaterialTheme.colorScheme.primary
 
@@ -101,153 +107,37 @@ fun CustomThemeScreen(
             // Color settings vs Seed color toggle based on enableDeepPersonalization
             if (enableDeepPersonalization) {
                 item {
-                    SplicedColumnGroup(title = stringResource(R.string.color_setting)) {
-                    // Primary colors
-                    ClickableSettingItem(
-                        title = stringResource(R.string.theme_manage_primary_color),
-                        option = if (themeColor != 0) "#${Integer.toHexString(themeColor).uppercase()}" else stringResource(R.string.click_to_select),
-                        onClick = {
-                            currentColorKey = "themeColor"
+                    CustomColorSettings(
+                        title = stringResource(R.string.day),
+                        primary = themeColor,
+                        secondary = secondaryThemeColor,
+                        primaryText = primaryTextColor,
+                        secondaryText = secondaryTextColor,
+                        background = themeBackgroundColor,
+                        labelContainer = labelContainerColor,
+                        keySuffix = "",
+                        onSelect = {
+                            currentColorKey = it
                             showColorPicker = true
                         },
-                        trailingContent = {
-                            if (themeColor != 0) {
-                                Box(
-                                    modifier = Modifier
-                                        .size(28.dp)
-                                        .clip(CircleShape)
-                                        .background(Color(themeColor))
-                                        .border(
-                                            1.dp,
-                                            MaterialTheme.colorScheme.outlineVariant,
-                                            CircleShape
-                                        )
-                                )
-                            }
-                        }
                     )
-
-                    ClickableSettingItem(
-                        title = stringResource(R.string.theme_manage_secondary_color),
-                        option = if (secondaryThemeColor != 0) "#${Integer.toHexString(secondaryThemeColor).uppercase()}" else stringResource(R.string.click_to_select),
-                        onClick = {
-                            currentColorKey = "secondaryThemeColor"
-                            showColorPicker = true
-                        },
-                        trailingContent = {
-                            if (secondaryThemeColor != 0) {
-                                Box(
-                                    modifier = Modifier
-                                        .size(28.dp)
-                                        .clip(CircleShape)
-                                        .background(Color(secondaryThemeColor))
-                                        .border(
-                                            1.dp,
-                                            MaterialTheme.colorScheme.outlineVariant,
-                                            CircleShape
-                                        )
-                                )
-                            }
-                        }
-                    )
-
-                    ClickableSettingItem(
-                        title = stringResource(R.string.theme_manage_primary_text_color),
-                        option = if (primaryTextColor != 0) "#${Integer.toHexString(primaryTextColor).uppercase()}" else stringResource(R.string.click_to_select),
-                        onClick = {
-                            currentColorKey = "primaryTextColor"
-                            showColorPicker = true
-                        },
-                        trailingContent = {
-                            if (primaryTextColor != 0) {
-                                Box(
-                                    modifier = Modifier
-                                        .size(28.dp)
-                                        .clip(CircleShape)
-                                        .background(Color(primaryTextColor))
-                                        .border(
-                                            1.dp,
-                                            MaterialTheme.colorScheme.outlineVariant,
-                                            CircleShape
-                                        )
-                                )
-                            }
-                        }
-                    )
-
-                    ClickableSettingItem(
-                        title = stringResource(R.string.theme_manage_secondary_text_color),
-                        option = if (secondaryTextColor != 0) "#${Integer.toHexString(secondaryTextColor).uppercase()}" else stringResource(R.string.click_to_select),
-                        onClick = {
-                            currentColorKey = "secondaryTextColor"
-                            showColorPicker = true
-                        },
-                        trailingContent = {
-                            if (secondaryTextColor != 0) {
-                                Box(
-                                    modifier = Modifier
-                                        .size(28.dp)
-                                        .clip(CircleShape)
-                                        .background(Color(secondaryTextColor))
-                                        .border(
-                                            1.dp,
-                                            MaterialTheme.colorScheme.outlineVariant,
-                                            CircleShape
-                                        )
-                                )
-                            }
-                        }
-                    )
-
-                    ClickableSettingItem(
-                        title = stringResource(R.string.theme_manage_background_color),
-                        option = if (themeBackgroundColor != 0) "#${Integer.toHexString(themeBackgroundColor).uppercase()}" else stringResource(R.string.click_to_select),
-                        onClick = {
-                            currentColorKey = "themeBackgroundColor"
-                            showColorPicker = true
-                        },
-                        trailingContent = {
-                            if (themeBackgroundColor != 0) {
-                                Box(
-                                    modifier = Modifier
-                                        .size(28.dp)
-                                        .clip(CircleShape)
-                                        .background(Color(themeBackgroundColor))
-                                        .border(
-                                            1.dp,
-                                            MaterialTheme.colorScheme.outlineVariant,
-                                            CircleShape
-                                        )
-                                )
-                            }
-                        }
-                    )
-
-                    ClickableSettingItem(
-                        title = stringResource(R.string.theme_manage_label_container_color),
-                        option = if (labelContainerColor != 0) "#${Integer.toHexString(labelContainerColor).uppercase()}" else stringResource(R.string.click_to_select),
-                        onClick = {
-                            currentColorKey = "labelContainerColor"
+                }
+                item {
+                    CustomColorSettings(
+                        title = stringResource(R.string.night),
+                        primary = themeColorNight,
+                        secondary = secondaryThemeColorNight,
+                        primaryText = primaryTextColorNight,
+                        secondaryText = secondaryTextColorNight,
+                        background = themeBackgroundColorNight,
+                        labelContainer = labelContainerColorNight,
+                        keySuffix = "Night",
+                        onSelect = {
+                            currentColorKey = it
                             showColorPicker = true
                         },
-                        trailingContent = {
-                            if (labelContainerColor != 0) {
-                                Box(
-                                    modifier = Modifier
-                                        .size(28.dp)
-                                        .clip(CircleShape)
-                                        .background(Color(labelContainerColor))
-                                        .border(
-                                            1.dp,
-                                            MaterialTheme.colorScheme.outlineVariant,
-                                            CircleShape
-                                        )
-                                )
-                            }
-                        }
                     )
                 }
-            }
             } else {
                 item {
                     SplicedColumnGroup(title = stringResource(R.string.custom_theme)) {
@@ -310,6 +200,12 @@ fun CustomThemeScreen(
                 "secondaryTextColor" -> secondaryTextColor
                 "themeBackgroundColor" -> themeBackgroundColor
                 "labelContainerColor" -> labelContainerColor
+                "themeColorNight" -> themeColorNight
+                "secondaryThemeColorNight" -> secondaryThemeColorNight
+                "primaryTextColorNight" -> primaryTextColorNight
+                "secondaryTextColorNight" -> secondaryTextColorNight
+                "themeBackgroundColorNight" -> themeBackgroundColorNight
+                "labelContainerColorNight" -> labelContainerColorNight
                 else -> 0
             },
             onDismissRequest = { showColorPicker = false },
@@ -321,6 +217,12 @@ fun CustomThemeScreen(
                     "secondaryTextColor" -> ThemeConfig.secondaryTextColor = it
                     "themeBackgroundColor" -> ThemeConfig.themeBackgroundColor = it
                     "labelContainerColor" -> ThemeConfig.labelContainerColor = it
+                    "themeColorNight" -> ThemeConfig.themeColorNight = it
+                    "secondaryThemeColorNight" -> ThemeConfig.secondaryThemeColorNight = it
+                    "primaryTextColorNight" -> ThemeConfig.primaryTextColorNight = it
+                    "secondaryTextColorNight" -> ThemeConfig.secondaryTextColorNight = it
+                    "themeBackgroundColorNight" -> ThemeConfig.themeBackgroundColorNight = it
+                    "labelContainerColorNight" -> ThemeConfig.labelContainerColorNight = it
                 }
             }
         )
@@ -357,6 +259,66 @@ fun CustomThemeScreen(
     }
 }
 
+@Composable
+private fun CustomColorSettings(
+    title: String,
+    primary: Int,
+    secondary: Int,
+    primaryText: Int,
+    secondaryText: Int,
+    background: Int,
+    labelContainer: Int,
+    keySuffix: String,
+    onSelect: (String) -> Unit,
+) {
+    SplicedColumnGroup(title = title) {
+        CustomColorSettingItem(
+            title = stringResource(R.string.theme_manage_primary_color),
+            colorValue = primary,
+            onClick = { onSelect("themeColor$keySuffix") },
+        )
+        CustomColorSettingItem(
+            title = stringResource(R.string.theme_manage_secondary_color),
+            colorValue = secondary,
+            onClick = { onSelect("secondaryThemeColor$keySuffix") },
+        )
+        CustomColorSettingItem(
+            title = stringResource(R.string.theme_manage_primary_text_color),
+            colorValue = primaryText,
+            onClick = { onSelect("primaryTextColor$keySuffix") },
+        )
+        CustomColorSettingItem(
+            title = stringResource(R.string.theme_manage_secondary_text_color),
+            colorValue = secondaryText,
+            onClick = { onSelect("secondaryTextColor$keySuffix") },
+        )
+        CustomColorSettingItem(
+            title = stringResource(R.string.theme_manage_background_color),
+            colorValue = background,
+            onClick = { onSelect("themeBackgroundColor$keySuffix") },
+        )
+        CustomColorSettingItem(
+            title = stringResource(R.string.theme_manage_label_container_color),
+            colorValue = labelContainer,
+            onClick = { onSelect("labelContainerColor$keySuffix") },
+        )
+    }
+}
+
+@Composable
+private fun CustomColorSettingItem(
+    title: String,
+    colorValue: Int,
+    onClick: () -> Unit,
+) {
+    ClickableSettingItem(
+        title = title,
+        option = formatColorOption(colorValue) ?: stringResource(R.string.click_to_select),
+        onClick = onClick,
+        trailingContent = { ColorSwatch(colorValue) },
+    )
+}
+
 private fun formatColorOption(colorValue: Int): String? {
     if (colorValue == 0) return null
     return "#${Integer.toHexString(colorValue).uppercase()}"

+ 55 - 0
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt

@@ -14,8 +14,27 @@ data class TagColorPair(
     val bgColor: Int = 0
 )
 
+data class CustomThemeColors(
+    val primary: Int,
+    val secondary: Int,
+    val primaryText: Int,
+    val secondaryText: Int,
+    val background: Int,
+    val labelContainer: Int,
+) {
+    val hasCustomColor: Boolean
+        get() = primary != 0 ||
+                secondary != 0 ||
+                primaryText != 0 ||
+                secondaryText != 0 ||
+                background != 0 ||
+                labelContainer != 0
+}
+
 object ThemeConfig {
 
+    private const val CUSTOM_APP_THEME = "12"
+
     var containerOpacity by prefDelegate(PreferKey.containerOpacity, 100)
 
     var topBarOpacity by prefDelegate(PreferKey.topBarOpacity, 100)
@@ -105,6 +124,42 @@ object ThemeConfig {
 
     var labelContainerColor by prefDelegate(PreferKey.labelContainerColor, 0)
 
+    var themeColorNight by prefDelegate(PreferKey.themeColorNight, 0)
+
+    var secondaryThemeColorNight by prefDelegate(PreferKey.secondaryThemeColorNight, 0)
+
+    var primaryTextColorNight by prefDelegate(PreferKey.primaryTextColorNight, 0)
+
+    var secondaryTextColorNight by prefDelegate(PreferKey.secondaryTextColorNight, 0)
+
+    var themeBackgroundColorNight by prefDelegate(PreferKey.themeBackgroundColorNight, 0)
+
+    var labelContainerColorNight by prefDelegate(PreferKey.labelContainerColorNight, 0)
+
+    val isDeepPersonalizationActive: Boolean
+        get() = appTheme == CUSTOM_APP_THEME && enableDeepPersonalization
+
+    fun customThemeColors(isDark: Boolean): CustomThemeColors {
+        if (!isDark) {
+            return CustomThemeColors(
+                primary = themeColor,
+                secondary = secondaryThemeColor,
+                primaryText = primaryTextColor,
+                secondaryText = secondaryTextColor,
+                background = themeBackgroundColor,
+                labelContainer = labelContainerColor,
+            )
+        }
+        return CustomThemeColors(
+            primary = themeColorNight.takeIf { it != 0 } ?: themeColor,
+            secondary = secondaryThemeColorNight.takeIf { it != 0 } ?: secondaryThemeColor,
+            primaryText = primaryTextColorNight.takeIf { it != 0 } ?: primaryTextColor,
+            secondaryText = secondaryTextColorNight.takeIf { it != 0 } ?: secondaryTextColor,
+            background = themeBackgroundColorNight.takeIf { it != 0 } ?: themeBackgroundColor,
+            labelContainer = labelContainerColorNight.takeIf { it != 0 } ?: labelContainerColor,
+        )
+    }
+
     var enableItemDivider by prefDelegate(PreferKey.enableItemDivider, false)
 
     var itemDividerWidth by prefDelegate(PreferKey.itemDividerWidth, 1f)

+ 32 - 0
app/src/main/java/io/legado/app/ui/config/themeManage/EditThemeSheet.kt

@@ -132,6 +132,7 @@ fun EditThemeSheet(
                 onCheckedChange = { data = data.copy(enableDeepPersonalization = !it) }
             )
             if (data.enableDeepPersonalization) {
+                SectionTitle(stringResource(R.string.day))
                 ColorItem(stringResource(R.string.theme_manage_primary_color), data.themeColor) {
                     currentColorKey = "themeColor"; showColorPicker = true
                 }
@@ -150,6 +151,25 @@ fun EditThemeSheet(
                 ColorItem(stringResource(R.string.theme_manage_label_container_color), data.labelContainerColor) {
                     currentColorKey = "labelContainerColor"; showColorPicker = true
                 }
+                SectionTitle(stringResource(R.string.night))
+                ColorItem(stringResource(R.string.theme_manage_primary_color), data.themeColorNight) {
+                    currentColorKey = "themeColorNight"; showColorPicker = true
+                }
+                ColorItem(stringResource(R.string.theme_manage_secondary_color), data.secondaryThemeColorNight) {
+                    currentColorKey = "secondaryThemeColorNight"; showColorPicker = true
+                }
+                ColorItem(stringResource(R.string.theme_manage_primary_text_color), data.primaryTextColorNight) {
+                    currentColorKey = "primaryTextColorNight"; showColorPicker = true
+                }
+                ColorItem(stringResource(R.string.theme_manage_secondary_text_color), data.secondaryTextColorNight) {
+                    currentColorKey = "secondaryTextColorNight"; showColorPicker = true
+                }
+                ColorItem(stringResource(R.string.theme_manage_background_color), data.themeBackgroundColorNight) {
+                    currentColorKey = "themeBackgroundColorNight"; showColorPicker = true
+                }
+                ColorItem(stringResource(R.string.theme_manage_label_container_color), data.labelContainerColorNight) {
+                    currentColorKey = "labelContainerColorNight"; showColorPicker = true
+                }
             } else {
                 ColorItem(stringResource(R.string.theme_manage_day_seed_color), data.cPrimary) {
                     currentColorKey = "cPrimary"; showColorPicker = true
@@ -310,6 +330,12 @@ fun EditThemeSheet(
             "secondaryTextColor" -> data.secondaryTextColor
             "themeBackgroundColor" -> data.themeBackgroundColor
             "labelContainerColor" -> data.labelContainerColor
+            "themeColorNight" -> data.themeColorNight
+            "secondaryThemeColorNight" -> data.secondaryThemeColorNight
+            "primaryTextColorNight" -> data.primaryTextColorNight
+            "secondaryTextColorNight" -> data.secondaryTextColorNight
+            "themeBackgroundColorNight" -> data.themeBackgroundColorNight
+            "labelContainerColorNight" -> data.labelContainerColorNight
             "cPrimary" -> data.cPrimary
             "cNPrimary" -> data.cNPrimary
             else -> 0
@@ -323,6 +349,12 @@ fun EditThemeSheet(
                 "secondaryTextColor" -> data.copy(secondaryTextColor = color)
                 "themeBackgroundColor" -> data.copy(themeBackgroundColor = color)
                 "labelContainerColor" -> data.copy(labelContainerColor = color)
+                "themeColorNight" -> data.copy(themeColorNight = color)
+                "secondaryThemeColorNight" -> data.copy(secondaryThemeColorNight = color)
+                "primaryTextColorNight" -> data.copy(primaryTextColorNight = color)
+                "secondaryTextColorNight" -> data.copy(secondaryTextColorNight = color)
+                "themeBackgroundColorNight" -> data.copy(themeBackgroundColorNight = color)
+                "labelContainerColorNight" -> data.copy(labelContainerColorNight = color)
                 "cPrimary" -> data.copy(cPrimary = color)
                 "cNPrimary" -> data.copy(cNPrimary = color)
                 else -> data

+ 27 - 4
app/src/main/java/io/legado/app/ui/config/themeManage/ThemeManageScreen.kt

@@ -301,13 +301,28 @@ private fun SavedThemeItem(
             else if (theme.data.cPrimary != 0) Color(theme.data.cPrimary)
             else MaterialTheme.colorScheme.primary
 
-            val darkPrimary = if (theme.data.cNPrimary != 0) Color(theme.data.cNPrimary)
-            else lightPrimary
+            val darkPrimary = if (theme.data.themeColorNight != 0) {
+                Color(theme.data.themeColorNight)
+            } else if (theme.data.cNPrimary != 0) {
+                Color(theme.data.cNPrimary)
+            } else {
+                lightPrimary
+            }
 
             val lightBg = if (theme.data.themeBackgroundColor != 0) Color(theme.data.themeBackgroundColor)
             else Color(0xFFF7F2FA)
 
-            val darkBg = if (theme.data.isPureBlack) Color.Black else Color(0xFF1C1B1F)
+            val darkBg = if (theme.data.themeBackgroundColorNight != 0) {
+                Color(theme.data.themeBackgroundColorNight)
+            } else if (theme.data.enableDeepPersonalization &&
+                theme.data.themeBackgroundColor != 0
+            ) {
+                Color(theme.data.themeBackgroundColor)
+            } else if (theme.data.isPureBlack) {
+                Color.Black
+            } else {
+                Color(0xFF1C1B1F)
+            }
 
             // 预览区域
             Column(
@@ -357,7 +372,15 @@ private fun SavedThemeItem(
                     AppText(
                         text = stringResource(R.string.theme_manage_preview_night),
                         style = MaterialTheme.typography.labelMediumEmphasized,
-                        color = Color.White.copy(alpha = 0.5f),
+                        color = if (theme.data.primaryTextColorNight != 0) {
+                            Color(theme.data.primaryTextColorNight).copy(alpha = 0.6f)
+                        } else if (theme.data.enableDeepPersonalization &&
+                            theme.data.primaryTextColor != 0
+                        ) {
+                            Color(theme.data.primaryTextColor).copy(alpha = 0.6f)
+                        } else {
+                            Color.White.copy(alpha = 0.5f)
+                        },
                         modifier = Modifier
                             .align(Alignment.CenterStart)
                             .padding(start = 12.dp)

+ 4 - 2
app/src/main/java/io/legado/app/ui/main/MainScreen.kt

@@ -79,6 +79,7 @@ import io.legado.app.ui.main.home.HomeRouteScreen
 import io.legado.app.ui.main.my.MyScreen
 import io.legado.app.ui.main.my.PrefClickEvent
 import io.legado.app.ui.main.rss.RssScreen
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.FloatingBottomBar
 import io.legado.app.ui.widget.components.FloatingBottomBarItem
@@ -172,8 +173,9 @@ fun MainScreen(
     }
 
     val hazeState = remember { HazeState() }
-    val floatingBarSurfaceColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-        Color(ThemeConfig.secondaryThemeColor)
+    val customSecondaryColor = ThemeConfig.customThemeColors(LegadoTheme.isDark).secondary
+    val floatingBarSurfaceColor = if (ThemeConfig.isDeepPersonalizationActive && customSecondaryColor != 0) {
+        Color(customSecondaryColor)
     } else {
         MaterialTheme.colorScheme.surface
     }

+ 12 - 17
app/src/main/java/io/legado/app/ui/theme/AppTheme.kt

@@ -35,12 +35,7 @@ fun AppTheme(
 
     // 2. 深度个性化配置
     val enableDeepPersonalization = ThemeConfig.enableDeepPersonalization
-    val themeColor = ThemeConfig.themeColor
-    val secondaryThemeColor = ThemeConfig.secondaryThemeColor
-    val primaryTextColor = ThemeConfig.primaryTextColor
-    val secondaryTextColor = ThemeConfig.secondaryTextColor
-    val themeBackgroundColor = ThemeConfig.themeBackgroundColor
-    val customLabelContainerColor = ThemeConfig.labelContainerColor
+    val customColors = ThemeConfig.customThemeColors(effectiveDarkTheme)
 
     // 3. 加载自定义字体
     val customFontFamily = rememberCustomFont(appFontPath)
@@ -48,20 +43,20 @@ fun AppTheme(
     // 4. 解析配色方案 (Material 3 ColorScheme)
     val colorScheme = remember(
         context, appThemeMode, effectiveDarkTheme, isPureBlack, customPrimary, customNightPrimary,
-        enableDeepPersonalization, themeColor, secondaryThemeColor, primaryTextColor,
-        secondaryTextColor, themeBackgroundColor, customLabelContainerColor,
+        enableDeepPersonalization, customColors,
         paletteStyleValue, materialVersion
     ) {
-        if (enableDeepPersonalization &&
-            (themeColor != 0 || secondaryThemeColor != 0 || primaryTextColor != 0 ||
-             secondaryTextColor != 0 || themeBackgroundColor != 0 || customLabelContainerColor != 0)) {
+        if (appThemeMode == AppThemeMode.Custom &&
+            enableDeepPersonalization &&
+            customColors.hasCustomColor
+        ) {
             val userPalette = UserColorPalette(
-                primaryColor = if (themeColor != 0) Color(themeColor) else Color(0xFF6750A4),
-                secondaryColor = if (secondaryThemeColor != 0) Color(secondaryThemeColor) else Color(0xFF625B71),
-                backgroundColor = if (themeBackgroundColor != 0) Color(themeBackgroundColor) else Color(0xFFFEF7FF),
-                primaryFontColor = if (primaryTextColor != 0) Color(primaryTextColor) else Color(0xFF1C1B1F),
-                secondaryFontColor = if (secondaryTextColor != 0) Color(secondaryTextColor) else Color(0xFF49454F),
-                labelContainerColor = if (customLabelContainerColor != 0) Color(customLabelContainerColor) else Color(0xFFF7F2FA)
+                primaryColor = if (customColors.primary != 0) Color(customColors.primary) else Color(0xFF6750A4),
+                secondaryColor = if (customColors.secondary != 0) Color(customColors.secondary) else Color(0xFF625B71),
+                backgroundColor = if (customColors.background != 0) Color(customColors.background) else Color(0xFFFEF7FF),
+                primaryFontColor = if (customColors.primaryText != 0) Color(customColors.primaryText) else Color(0xFF1C1B1F),
+                secondaryFontColor = if (customColors.secondaryText != 0) Color(customColors.secondaryText) else Color(0xFF49454F),
+                labelContainerColor = if (customColors.labelContainer != 0) Color(customColors.labelContainer) else Color(0xFFF7F2FA)
             )
             generateColorScheme(userPalette, effectiveDarkTheme)
         } else {

+ 13 - 18
app/src/main/java/io/legado/app/ui/theme/ThemeComponents.kt

@@ -108,14 +108,20 @@ fun MiuixThemeWrapper(
         }
 
         val miuixColorScheme = MiuixTheme.colorScheme
-        val mappedColorScheme = remember(miuixColorScheme) {
-            val customBgColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.themeBackgroundColor != 0) {
-                Color(ThemeConfig.themeBackgroundColor)
+        val customColors = ThemeConfig.customThemeColors(darkTheme)
+        val isDeepPersonalizationActive = ThemeConfig.isDeepPersonalizationActive
+        val mappedColorScheme = remember(
+            miuixColorScheme,
+            customColors,
+            isDeepPersonalizationActive,
+        ) {
+            val customBgColor = if (isDeepPersonalizationActive && customColors.background != 0) {
+                Color(customColors.background)
             } else {
                 miuixColorScheme.background
             }
-            val customFontColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.primaryTextColor != 0) {
-                Color(ThemeConfig.primaryTextColor)
+            val customFontColor = if (isDeepPersonalizationActive && customColors.primaryText != 0) {
+                Color(customColors.primaryText)
             } else {
                 miuixColorScheme.onSurface
             }
@@ -237,20 +243,9 @@ fun MaterialThemeWrapper(
             materialTypography.toLegadoTypography().withFont(customFontFamily)
         }
         val semanticColors = remember(colorScheme) {
-            val customBgColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.themeBackgroundColor != 0) {
-                Color(ThemeConfig.themeBackgroundColor)
-            } else {
-                colorScheme.background
-            }
-            val customFontColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.primaryTextColor != 0) {
-                Color(ThemeConfig.primaryTextColor)
-            } else {
-                colorScheme.onSurface
-            }
-
             colorScheme.toLegadoColorScheme(
-                customBgColor = customBgColor,
-                customFontColor = customFontColor,
+                customBgColor = colorScheme.background,
+                customFontColor = colorScheme.onSurface,
                 customTopBarColor = colorScheme.surface,
                 customNavBarColor = colorScheme.surface
             )

+ 5 - 4
app/src/main/java/io/legado/app/ui/widget/components/FloatingBottomBar.kt

@@ -130,13 +130,14 @@ fun FloatingBottomBar(
     content: @Composable RowScope.() -> Unit
 ) {
     val isInLightTheme = !LegadoTheme.isDark
-    val accentColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.themeColor != 0) {
-        Color(ThemeConfig.themeColor)
+    val customColors = ThemeConfig.customThemeColors(LegadoTheme.isDark)
+    val accentColor = if (ThemeConfig.isDeepPersonalizationActive && customColors.primary != 0) {
+        Color(customColors.primary)
     } else {
         LegadoTheme.colorScheme.primary
     }
-    val containerColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-        Color(ThemeConfig.secondaryThemeColor).copy(alpha = if (isBlurEnabled) ThemeConfig.bottomBarBlurAlpha / 100f else 1f)
+    val containerColor = if (ThemeConfig.isDeepPersonalizationActive && customColors.secondary != 0) {
+        Color(customColors.secondary).copy(alpha = if (isBlurEnabled) ThemeConfig.bottomBarBlurAlpha / 100f else 1f)
     } else if (isBlurEnabled) {
         LegadoTheme.colorScheme.surfaceContainer.copy(alpha = ThemeConfig.bottomBarBlurAlpha / 100f)
     } else {

+ 4 - 2
app/src/main/java/io/legado/app/ui/widget/components/GlassDefaults.kt

@@ -3,6 +3,7 @@ package io.legado.app.ui.widget.components
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.Color
 import io.legado.app.ui.config.themeConfig.ThemeConfig
+import io.legado.app.ui.theme.LegadoTheme
 
 object GlassDefaults {
 
@@ -22,8 +23,9 @@ object GlassDefaults {
 
     @Composable
     fun secondaryColorOr(fallback: @Composable () -> Color): Color {
-        return if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
+        val secondaryColor = ThemeConfig.customThemeColors(LegadoTheme.isDark).secondary
+        return if (ThemeConfig.isDeepPersonalizationActive && secondaryColor != 0) {
+            Color(secondaryColor)
         } else {
             fallback()
         }

+ 5 - 4
app/src/main/java/io/legado/app/ui/widget/components/navigation/AppNavigationBar.kt

@@ -50,6 +50,7 @@ fun AppNavigationBar(
         else -> NavigationBarDisplayMode.IconWithSelectedLabel
     }
     val opacity = (ThemeConfig.bottomBarOpacity.coerceIn(0, 100)) / 100f
+    val customSecondaryColor = ThemeConfig.customThemeColors(LegadoTheme.isDark).secondary
     val hazeState = LocalHazeState.current
     val hazeModifier = if (hazeState != null) {
         Modifier.regularHazeEffect(hazeState)
@@ -59,8 +60,8 @@ fun AppNavigationBar(
 
     if (isMiuix) {
         val baseColor =
-            if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-                Color(ThemeConfig.secondaryThemeColor)
+            if (ThemeConfig.isDeepPersonalizationActive && customSecondaryColor != 0) {
+                Color(customSecondaryColor)
             } else {
                 GlassDefaults.glassColor(
                     noBlurColor = MiuixTheme.colorScheme.surface,
@@ -77,8 +78,8 @@ fun AppNavigationBar(
         )
     } else {
         val baseColor =
-            if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-                Color(ThemeConfig.secondaryThemeColor)
+            if (ThemeConfig.isDeepPersonalizationActive && customSecondaryColor != 0) {
+                Color(customSecondaryColor)
             } else {
                 GlassDefaults.glassColor(
                     noBlurColor = BottomAppBarDefaults.containerColor,

+ 9 - 39
app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt

@@ -51,31 +51,15 @@ fun GlassMediumFlexibleTopAppBar(
     val isMiuix = ThemeResolver.isMiuixEngine(composeEngine)
 
     val containerColor = if (!isMiuix) {
-        if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
-            GlassTopAppBarDefaults.containerColor()
-        }
+        GlassDefaults.secondaryColorOr { GlassTopAppBarDefaults.containerColor() }
     } else {
-        if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
-            GlassTopAppBarDefaults.getMiuixAppBarColor()
-        }
+        GlassDefaults.secondaryColorOr { GlassTopAppBarDefaults.getMiuixAppBarColor() }
     }
 
     val scrolledColor = if (!isMiuix) {
-        if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
-            GlassTopAppBarDefaults.scrolledContainerColor()
-        }
+        GlassDefaults.secondaryColorOr { GlassTopAppBarDefaults.scrolledContainerColor() }
     } else {
-        if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
-            GlassTopAppBarDefaults.getMiuixAppBarColor()
-        }
+        GlassDefaults.secondaryColorOr { GlassTopAppBarDefaults.getMiuixAppBarColor() }
     }
 
     val animatedColor = if (!isMiuix) {
@@ -190,11 +174,7 @@ object GlassTopAppBarDefaults {
 
     @Composable
     fun getMiuixAppBarColor(): Color {
-        val baseColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
-            MiuixTheme.colorScheme.surface
-        }
+        val baseColor = GlassDefaults.secondaryColorOr { MiuixTheme.colorScheme.surface }
         return GlassDefaults.glassColor(
             noBlurColor = baseColor,
             blurAlpha = GlassDefaults.TransparentAlpha
@@ -218,9 +198,7 @@ object GlassTopAppBarDefaults {
     @Composable
     fun glassColors(): TopAppBarColors {
 
-        val containerBaseColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
+        val containerBaseColor = GlassDefaults.secondaryColorOr {
             MaterialTheme.colorScheme.surface
         }
         val containerColor = GlassDefaults.glassColor(
@@ -228,9 +206,7 @@ object GlassTopAppBarDefaults {
             blurAlpha = GlassDefaults.TransparentAlpha
         )
 
-        val scrolledBaseColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
+        val scrolledBaseColor = GlassDefaults.secondaryColorOr {
             MaterialTheme.colorScheme.surfaceContainer
         }
         val scrolledContainerColor = if (ThemeConfig.enableBlur) {
@@ -247,11 +223,7 @@ object GlassTopAppBarDefaults {
 
     @Composable
     fun containerColor(): Color {
-        val baseColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
-            MaterialTheme.colorScheme.surface
-        }
+        val baseColor = GlassDefaults.secondaryColorOr { MaterialTheme.colorScheme.surface }
         val glassColor = GlassDefaults.glassColor(
             noBlurColor = baseColor,
             blurAlpha = GlassDefaults.TransparentAlpha
@@ -261,9 +233,7 @@ object GlassTopAppBarDefaults {
 
     @Composable
     fun scrolledContainerColor(): Color {
-        val baseColor = if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) {
-            Color(ThemeConfig.secondaryThemeColor)
-        } else {
+        val baseColor = GlassDefaults.secondaryColorOr {
             MaterialTheme.colorScheme.surfaceContainer
         }
         val glassColor = GlassDefaults.glassColor(