Просмотр исходного кода

fix: 为阅读界面相关颜色设置提供亮暗两套色值,优化菜单展开时的模糊半径

HapeLee 4 месяцев назад
Родитель
Сommit
43a07a28a2

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

@@ -321,6 +321,7 @@ object PreferKey {
     const val readMenuBlurRadius = "readMenuBlurRadius"
     const val readMenuBlurAlpha = "readMenuBlurAlpha"
     const val readMenuBlurColor = "readMenuBlurColor"
+    const val readMenuBlurColorNight = "readMenuBlurColorNight"
     const val readMenuPaletteStyle = "readMenuPaletteStyle"
     const val readMenuLensRadius = "readMenuLensRadius"
     const val readMenuBorderWidth = "readMenuBorderWidth"

+ 6 - 0
app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt

@@ -97,6 +97,7 @@ data class ReadPreferences(
     val readMenuBlurRadius: Int = 24,
     val readMenuBlurAlpha: Int = 60,
     val readMenuBlurColor: Int = 0,
+    val readMenuBlurColorNight: Int = 0,
     val readMenuPaletteStyle: String = "",
     val readMenuLensRadius: Float = 24f,
     val readMenuBorderWidth: Int = 0,
@@ -349,6 +350,9 @@ class ReadSettingsRepository(
     suspend fun setReadMenuBlurColor(value: Int) =
         settingsRepository.putInt(PreferKey.readMenuBlurColor, value)
 
+    suspend fun setReadMenuBlurColorNight(value: Int) =
+        settingsRepository.putInt(PreferKey.readMenuBlurColorNight, value)
+
     suspend fun setReadMenuPaletteStyle(value: String) =
         settingsRepository.putString(PreferKey.readMenuPaletteStyle, value)
 
@@ -478,6 +482,7 @@ class ReadSettingsRepository(
             readMenuBlurRadius = this[Keys.ReadMenuBlurRadius] ?: 24,
             readMenuBlurAlpha = this[Keys.ReadMenuBlurAlpha] ?: 60,
             readMenuBlurColor = this[Keys.ReadMenuBlurColor] ?: 0,
+            readMenuBlurColorNight = this[Keys.ReadMenuBlurColorNight] ?: 0,
             readMenuPaletteStyle = this[Keys.ReadMenuPaletteStyle] ?: "",
             readMenuLensRadius = this[Keys.ReadMenuLensRadius] ?: 24f,
             readMenuBorderWidth = this[Keys.ReadMenuBorderWidth] ?: 0,
@@ -577,6 +582,7 @@ class ReadSettingsRepository(
         val ReadMenuBlurRadius = intPreferencesKey(PreferKey.readMenuBlurRadius)
         val ReadMenuBlurAlpha = intPreferencesKey(PreferKey.readMenuBlurAlpha)
         val ReadMenuBlurColor = intPreferencesKey(PreferKey.readMenuBlurColor)
+        val ReadMenuBlurColorNight = intPreferencesKey(PreferKey.readMenuBlurColorNight)
         val ReadMenuPaletteStyle = stringPreferencesKey(PreferKey.readMenuPaletteStyle)
         val ReadMenuLensRadius = floatPreferencesKey(PreferKey.readMenuLensRadius)
         val ReadMenuBorderWidth = intPreferencesKey(PreferKey.readMenuBorderWidth)

+ 46 - 0
app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt

@@ -115,6 +115,12 @@ object ReadBookConfig {
     var bg: Drawable? = null
     var bgMeanColor: Int = 0
     val textColor: Int get() = durConfig.curTextColor()
+    val textColorNight: Int
+        get() = try {
+            durConfig.getTextColorNight().toColorInt()
+        } catch (_: Exception) {
+            0xFFADADAD.toInt()
+        }
     val textAccentColor: Int get() = durConfig.curTextAccentColor()
     val textShadowColor: Int get() = durConfig.curTextShadowColor()
     val menuColor: Int get() = readMenuAccentColor
@@ -240,6 +246,7 @@ object ReadBookConfig {
     var readMenuBlurRadius by clampedPrefDelegate(PreferKey.readMenuBlurRadius, 24, 0..32)
     var readMenuBlurAlpha by clampedPrefDelegate(PreferKey.readMenuBlurAlpha, 60, 0..100)
     var readMenuBlurColor by prefDelegate(PreferKey.readMenuBlurColor, 0)
+    var readMenuBlurColorNight by prefDelegate(PreferKey.readMenuBlurColorNight, 0)
     var readMenuPaletteStyle: String = ""
     var readMenuLensRadius by clampedPrefDelegate(PreferKey.readMenuLensRadius, 24f, 0f..48f)
     var readMenuBorderWidth by clampedPrefDelegate(PreferKey.readMenuBorderWidth, 0, 0..4)
@@ -343,6 +350,9 @@ object ReadBookConfig {
     val resolvedMenuBorderColor: Int
         get() = if (ReadStyleResolver.isNightTheme()) readMenuBorderColorNight else readMenuBorderColor
 
+    val resolvedMenuBlurColor: Int
+        get() = if (ReadStyleResolver.isNightTheme()) readMenuBlurColorNight else readMenuBlurColor
+
 
     val config get() = if (shareLayout) shareConfig else durConfig
 
@@ -533,6 +543,15 @@ object ReadBookConfig {
             config.titleColor = value
         }
 
+    var titleColorNight: Int
+        get() = config.titleColorNight
+        set(value) {
+            config.titleColorNight = value
+        }
+
+    val resolvedTitleColor: Int
+        get() = if (ReadStyleResolver.isNightTheme()) titleColorNight else titleColor
+
     var paragraphIndent: String
         get() = config.paragraphIndent
         set(value) {
@@ -745,12 +764,30 @@ object ReadBookConfig {
             config.tipHeaderColor = value
         }
 
+    var tipHeaderColorNight: Int
+        get() = config.tipHeaderColorNight
+        set(value) {
+            config.tipHeaderColorNight = value
+        }
+
+    val resolvedTipHeaderColor: Int
+        get() = if (ReadStyleResolver.isNightTheme()) tipHeaderColorNight else tipHeaderColor
+
     var tipFooterColor: Int
         get() = config.tipFooterColor
         set(value) {
             config.tipFooterColor = value
         }
 
+    var tipFooterColorNight: Int
+        get() = config.tipFooterColorNight
+        set(value) {
+            config.tipFooterColorNight = value
+        }
+
+    val resolvedTipFooterColor: Int
+        get() = if (ReadStyleResolver.isNightTheme()) tipFooterColorNight else tipFooterColor
+
     var tipDividerColor: Int
         get() = config.tipDividerColor
         set(value) {
@@ -803,6 +840,7 @@ object ReadBookConfig {
             exportConfig.titleTopSpacing = shareConfig.titleTopSpacing
             exportConfig.titleBottomSpacing = shareConfig.titleBottomSpacing
             exportConfig.titleColor = shareConfig.titleColor
+            exportConfig.titleColorNight = shareConfig.titleColorNight
             exportConfig.paddingBottom = shareConfig.paddingBottom
             exportConfig.paddingLeft = shareConfig.paddingLeft
             exportConfig.paddingRight = shareConfig.paddingRight
@@ -824,7 +862,9 @@ object ReadBookConfig {
             exportConfig.tipFooterMiddle = shareConfig.tipFooterMiddle
             exportConfig.tipFooterRight = shareConfig.tipFooterRight
             exportConfig.tipHeaderColor = shareConfig.tipHeaderColor
+            exportConfig.tipHeaderColorNight = shareConfig.tipHeaderColorNight
             exportConfig.tipFooterColor = shareConfig.tipFooterColor
+            exportConfig.tipFooterColorNight = shareConfig.tipFooterColorNight
             exportConfig.headerMode = shareConfig.headerMode
             // MD3专有属性
             exportConfig.footerMode = shareConfig.footerMode
@@ -916,6 +956,7 @@ object ReadBookConfig {
         var titleTopSpacing: Int = 0,
         var titleBottomSpacing: Int = 0,
         var titleColor: Int = 0,
+        var titleColorNight: Int = 0,
         var titleBold: Int = 500,//是否粗体字 0:正常, 1:粗体, 2:细体
         var titleLineSpacingExtra: Int = 12,
         var titleLineSpacingSub: Int = 12,
@@ -954,7 +995,9 @@ object ReadBookConfig {
         var tipFooterMiddle: Int = tipNone,
         var tipFooterRight: Int = tipPageAndTotal,
         var tipHeaderColor: Int = 0,
+        var tipHeaderColorNight: Int = 0,
         var tipFooterColor: Int = 0,
+        var tipFooterColorNight: Int = 0,
         var tipDividerColor: Int = -1,
         var headerMode: Int = 0,
         var footerMode: Int = 0,
@@ -1065,6 +1108,7 @@ object ReadBookConfig {
             "titleTopSpacing" to titleTopSpacing,
             "titleBottomSpacing" to titleBottomSpacing,
             "titleColor" to titleColor,
+            "titleColorNight" to titleColorNight,
             "paragraphIndent" to paragraphIndent,
             "paddingBottom" to paddingBottom,
             "paddingLeft" to paddingLeft,
@@ -1087,7 +1131,9 @@ object ReadBookConfig {
             "tipFooterMiddle" to tipFooterMiddle,
             "tipFooterRight" to tipFooterRight,
             "tipHeaderColor" to tipHeaderColor,
+            "tipHeaderColorNight" to tipHeaderColorNight,
             "tipFooterColor" to tipFooterColor,
+            "tipFooterColorNight" to tipFooterColorNight,
             "tipDividerColor" to tipDividerColor,
             "headerMode" to headerMode,
             "footerMode" to footerMode,

+ 13 - 0
app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt

@@ -292,6 +292,7 @@ data class ReadMenuConfig(
     val readMenuBorderColorNight: Int = 0,
     val readMenuBlurAlpha: Int = 60,
     val readMenuBlurColor: Int = 0,
+    val readMenuBlurColorNight: Int = 0,
     val readMenuPaletteStyle: String = "",
     val readMenuBlurRadius: Int = 24,
     val readMenuLensRadius: Float = 24f,
@@ -965,6 +966,9 @@ sealed interface ConfigUpdate {
     data class TitleColor(val color: Int) : ConfigUpdate {
         override val actions = setOf(ConfigUpdateAction.UpdateStyle, ConfigUpdateAction.ReloadContent, ConfigUpdateAction.InvalidateTextPage)
     }
+    data class TitleColorNight(val color: Int) : ConfigUpdate {
+        override val actions = setOf(ConfigUpdateAction.UpdateStyle, ConfigUpdateAction.ReloadContent, ConfigUpdateAction.InvalidateTextPage)
+    }
     data class TitleFont(val path: String) : ConfigUpdate {
         override val actions = setOf(ConfigUpdateAction.UpdateChapterStyle, ConfigUpdateAction.ReloadContent)
     }
@@ -1012,9 +1016,15 @@ sealed interface ConfigUpdate {
     data class TipHeaderColor(val color: Int) : ConfigUpdate {
         override val actions = setOf(ConfigUpdateAction.UpdateStyle)
     }
+    data class TipHeaderColorNight(val color: Int) : ConfigUpdate {
+        override val actions = setOf(ConfigUpdateAction.UpdateStyle)
+    }
     data class TipFooterColor(val color: Int) : ConfigUpdate {
         override val actions = setOf(ConfigUpdateAction.UpdateStyle)
     }
+    data class TipFooterColorNight(val color: Int) : ConfigUpdate {
+        override val actions = setOf(ConfigUpdateAction.UpdateStyle)
+    }
     data class TipDividerColor(val color: Int) : ConfigUpdate {
         override val actions = setOf(ConfigUpdateAction.UpdateStyle)
     }
@@ -1249,6 +1259,9 @@ sealed interface ConfigUpdate {
     data class MenuBlurColor(val color: Int) : ConfigUpdate {
         override val actions = emptySet<ConfigUpdateAction>()
     }
+    data class MenuBlurColorNight(val color: Int) : ConfigUpdate {
+        override val actions = emptySet<ConfigUpdateAction>()
+    }
     data class MenuPaletteStyle(val value: String) : ConfigUpdate {
         override val actions = emptySet<ConfigUpdateAction>()
     }

+ 26 - 5
app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt

@@ -563,6 +563,7 @@ private fun ReadBookMenuSurface(
                         shape = surfaceShape,
                         menuConfig = state.menuConfig,
                         progressive = bottomBarProgressiveBlur,
+                        blurRadiusDp = if (expanded) 32 else null,
                     )
                 } else {
                     Modifier
@@ -588,9 +589,18 @@ private fun ReadBookMenuSurface(
                 }
             },
         shape = surfaceShape,
-        color = if (useLiquidGlass || useHaze) Color.Transparent else colors.background.copy(
-            alpha = state.menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f
-        ),
+        color = if (useLiquidGlass || useHaze) {
+            if (bottomBarProgressiveBlur) {
+                // Stable opaque background prevents flash during Haze recomposition
+                colors.background.copy(alpha = state.menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f)
+            } else {
+                Color.Transparent
+            }
+        } else {
+            val baseAlpha = state.menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f
+            val effectiveAlpha = if (expanded) baseAlpha.coerceAtLeast(0.85f) else baseAlpha
+            colors.background.copy(alpha = effectiveAlpha)
+        },
         contentColor = colors.content
     ) {
         AnimatedContent(
@@ -3082,6 +3092,7 @@ private fun Modifier.readMenuBottomBarHazeEffect(
     shape: Shape,
     menuConfig: ReadMenuConfig,
     progressive: Boolean,
+    blurRadiusDp: Int? = null,
 ): Modifier {
     val surfaceAlpha = menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f
     val backgroundModifier = if (progressive) {
@@ -3102,6 +3113,7 @@ private fun Modifier.readMenuBottomBarHazeEffect(
             menuConfig = menuConfig,
             progressive = progressive,
             progressiveBottomToTop = progressive,
+            blurRadiusDp = blurRadiusDp,
         )
 }
 
@@ -3113,9 +3125,18 @@ private fun Modifier.readMenuHazeEffect(
     menuConfig: ReadMenuConfig,
     progressive: Boolean = false,
     progressiveBottomToTop: Boolean = false,
+    blurRadiusDp: Int? = null,
 ): Modifier {
     val surfaceAlpha = menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f
-    val blurTintColor = menuConfig.readMenuBlurColor.takeIf { it != 0 }?.let { Color(it) }
+    val blurTintColor = menuConfig.readMenuBlurColorNight
+        .takeIf { it != 0 && ReadStyleResolver.isNightTheme() }
+        ?.let { Color(it) }
+        ?: menuConfig.readMenuBlurColor
+            .takeIf { it != 0 && !ReadStyleResolver.isNightTheme() }
+            ?.let { Color(it) }
+            ?: menuConfig.readMenuBlurColor
+                .takeIf { it != 0 }
+                ?.let { Color(it) }
     val hazeContainerColor = if (progressive) {
         (blurTintColor ?: Color.Black).copy(alpha = surfaceAlpha)
     } else {
@@ -3123,7 +3144,7 @@ private fun Modifier.readMenuHazeEffect(
     }
     val style = HazeLegado.custom(
         containerColor = hazeContainerColor,
-        blurRadius = menuConfig.readMenuBlurRadius,
+        blurRadius = blurRadiusDp ?: menuConfig.readMenuBlurRadius,
         blurAlpha = menuConfig.readMenuBlurAlpha,
     )
 

+ 11 - 0
app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt

@@ -2042,6 +2042,7 @@ class ReadBookViewModel(
                 readMenuBorderColorNight = ReadBookConfig.readMenuBorderColorNight,
                 readMenuBlurAlpha = ReadBookConfig.readMenuBlurAlpha,
                 readMenuBlurColor = ReadBookConfig.readMenuBlurColor,
+                readMenuBlurColorNight = ReadBookConfig.readMenuBlurColorNight,
                 readMenuPaletteStyle = ReadBookConfig.readMenuPaletteStyle,
                 readMenuBlurRadius = ReadBookConfig.readMenuBlurRadius,
                 readMenuLensRadius = ReadBookConfig.readMenuLensRadius,
@@ -4343,6 +4344,7 @@ class ReadBookViewModel(
             is ConfigUpdate.TitleTopSpacing -> ReadBookConfig.titleTopSpacing = update.value
             is ConfigUpdate.TitleBottomSpacing -> ReadBookConfig.titleBottomSpacing = update.value
             is ConfigUpdate.TitleColor -> ReadBookConfig.titleColor = update.color
+            is ConfigUpdate.TitleColorNight -> ReadBookConfig.titleColorNight = update.color
             is ConfigUpdate.TitleFont -> ReadBookConfig.titleFont = update.path
             is ConfigUpdate.TitleSegType -> ReadBookConfig.titleSegType = update.value
             is ConfigUpdate.TitleSegDistance -> ReadBookConfig.titleSegDistance = update.value
@@ -4360,7 +4362,9 @@ class ReadBookViewModel(
             is ConfigUpdate.HeaderFont -> ReadBookConfig.headerFont = update.path
             is ConfigUpdate.HeaderFontSize -> ReadBookConfig.headerFontSize = update.value
             is ConfigUpdate.TipHeaderColor -> ReadBookConfig.tipHeaderColor = update.color
+            is ConfigUpdate.TipHeaderColorNight -> ReadBookConfig.tipHeaderColorNight = update.color
             is ConfigUpdate.TipFooterColor -> ReadBookConfig.tipFooterColor = update.color
+            is ConfigUpdate.TipFooterColorNight -> ReadBookConfig.tipFooterColorNight = update.color
             is ConfigUpdate.TipDividerColor -> ReadBookConfig.tipDividerColor = update.color
 
             // --- Layout / style ---
@@ -4683,6 +4687,13 @@ class ReadBookViewModel(
                 }
                 _uiState.update { it.copy(menuConfig = it.menuConfig.copy(readMenuBlurColor = update.color)) }
             }
+            is ConfigUpdate.MenuBlurColorNight -> {
+                ReadBookConfig.readMenuBlurColorNight = update.color
+                viewModelScope.launch {
+                    readSettingsRepository.setReadMenuBlurColorNight(update.color)
+                }
+                _uiState.update { it.copy(menuConfig = it.menuConfig.copy(readMenuBlurColorNight = update.color)) }
+            }
             is ConfigUpdate.MenuPaletteStyle -> {
                 ReadBookConfig.readMenuPaletteStyle = update.value
                 viewModelScope.launch {

+ 2 - 2
app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt

@@ -120,10 +120,10 @@ class PageView(
         ReadBookConfig.let {
             val textColor = it.textColor
             val headerColor = with(ReadBookConfig) {
-                if (tipHeaderColor == 0) textColor else tipHeaderColor
+                if (resolvedTipHeaderColor == 0) textColor else resolvedTipHeaderColor
             }
             val footerColor = with(ReadBookConfig) {
-                if (tipFooterColor == 0) textColor else tipFooterColor
+                if (resolvedTipFooterColor == 0) textColor else resolvedTipFooterColor
             }
             val tipDividerColor = with(ReadBookConfig) {
                 when (tipDividerColor) {

+ 2 - 2
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt

@@ -199,8 +199,8 @@ data class TextLine(
         }
         val textColor = if (isReadAloud) {
             ReadBookConfig.textAccentColor
-        } else if (isTitle && ReadBookConfig.titleColor != 0) {
-            ReadBookConfig.titleColor
+        } else if (isTitle && ReadBookConfig.resolvedTitleColor != 0) {
+            ReadBookConfig.resolvedTitleColor
         } else {
             ReadBookConfig.textColor
         }

+ 2 - 2
app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt

@@ -63,8 +63,8 @@ data class TextColumn(
         val drawColor = if (textLine.isReadAloud || isSearchResult) {
             ReadBookConfig.textAccentColor
         } else {
-            textColor ?: if (textLine.isTitle && ReadBookConfig.titleColor != 0) {
-                ReadBookConfig.titleColor
+            textColor ?: if (textLine.isTitle && ReadBookConfig.resolvedTitleColor != 0) {
+                ReadBookConfig.resolvedTitleColor
             } else {
                 ReadBookConfig.textColor
             }

+ 67 - 14
app/src/main/java/io/legado/app/ui/book/read/sheet/HeaderFooterPage.kt

@@ -58,6 +58,7 @@ import io.legado.app.ui.widget.components.pager.pagerHeight
 import io.legado.app.ui.widget.components.pager.rememberPagerAnimatedHeight
 import io.legado.app.ui.widget.components.pager.rememberPagerFlingPassThroughConnection
 import io.legado.app.ui.widget.components.settingItem.TinyClickableSettingItem
+import io.legado.app.ui.widget.components.settingItem.TinyColorModeSettingItem
 import io.legado.app.ui.widget.components.settingItem.TinyColorSettingItem
 import io.legado.app.ui.widget.components.settingItem.TinyDropdownSettingItem
 import io.legado.app.ui.widget.components.settingItem.TinySliderSettingItem
@@ -71,6 +72,8 @@ import org.koin.compose.koinInject
 private const val COLOR_HEADER = 7
 private const val COLOR_FOOTER = 8
 private const val COLOR_DIVIDER = 9
+private const val COLOR_HEADER_NIGHT = 10
+private const val COLOR_FOOTER_NIGHT = 11
 
 @Composable
 internal fun HeaderFooterPage(
@@ -295,23 +298,44 @@ internal fun HeaderFooterPage(
                                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderRight(it)))
                             },
                         )
-                        TinyColorSettingItem(
+                        TinyColorModeSettingItem(
                             title = stringResource(R.string.header_color),
-                            colorValue = if (ReadBookConfig.tipHeaderColor != 0) {
+                            dayColor = if (ReadBookConfig.tipHeaderColor != 0) {
                                 ReadBookConfig.tipHeaderColor
                             } else {
                                 ReadBookConfig.textColor
                             },
-                            onClick = {
-                                colorPickerId = COLOR_HEADER
-                                colorPickerInitial = if (ReadBookConfig.tipHeaderColor != 0) {
-                                    ReadBookConfig.tipHeaderColor
+                            nightColor = if (ReadBookConfig.tipHeaderColorNight != 0) {
+                                ReadBookConfig.tipHeaderColorNight
+                            } else {
+                                ReadBookConfig.textColorNight
+                            },
+                            onClickColor = { isNight ->
+                                if (isNight) {
+                                    colorPickerId = COLOR_HEADER_NIGHT
+                                    colorPickerInitial = if (ReadBookConfig.tipHeaderColorNight != 0) {
+                                        ReadBookConfig.tipHeaderColorNight
+                                    } else {
+                                        ReadBookConfig.textColorNight
+                                    }
                                 } else {
-                                    ReadBookConfig.textColor
+                                    colorPickerId = COLOR_HEADER
+                                    colorPickerInitial = if (ReadBookConfig.tipHeaderColor != 0) {
+                                        ReadBookConfig.tipHeaderColor
+                                    } else {
+                                        ReadBookConfig.textColor
+                                    }
                                 }
                                 showColorPicker = true
                             },
                         )
+                        TinyClickableSettingItem(
+                            title = stringResource(R.string.reset_to_body_color),
+                            onClick = {
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderColor(0)))
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderColorNight(0)))
+                            },
+                        )
 
                         TinyClickableSettingItem(
                             title = stringResource(R.string.padding),
@@ -425,23 +449,44 @@ internal fun HeaderFooterPage(
                                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterRight(it)))
                             },
                         )
-                        TinyColorSettingItem(
+                        TinyColorModeSettingItem(
                             title = stringResource(R.string.footer_color),
-                            colorValue = if (ReadBookConfig.tipFooterColor != 0) {
+                            dayColor = if (ReadBookConfig.tipFooterColor != 0) {
                                 ReadBookConfig.tipFooterColor
                             } else {
                                 ReadBookConfig.textColor
                             },
-                            onClick = {
-                                colorPickerId = COLOR_FOOTER
-                                colorPickerInitial = if (ReadBookConfig.tipFooterColor != 0) {
-                                    ReadBookConfig.tipFooterColor
+                            nightColor = if (ReadBookConfig.tipFooterColorNight != 0) {
+                                ReadBookConfig.tipFooterColorNight
+                            } else {
+                                ReadBookConfig.textColorNight
+                            },
+                            onClickColor = { isNight ->
+                                if (isNight) {
+                                    colorPickerId = COLOR_FOOTER_NIGHT
+                                    colorPickerInitial = if (ReadBookConfig.tipFooterColorNight != 0) {
+                                        ReadBookConfig.tipFooterColorNight
+                                    } else {
+                                        ReadBookConfig.textColorNight
+                                    }
                                 } else {
-                                    ReadBookConfig.textColor
+                                    colorPickerId = COLOR_FOOTER
+                                    colorPickerInitial = if (ReadBookConfig.tipFooterColor != 0) {
+                                        ReadBookConfig.tipFooterColor
+                                    } else {
+                                        ReadBookConfig.textColor
+                                    }
                                 }
                                 showColorPicker = true
                             },
                         )
+                        TinyClickableSettingItem(
+                            title = stringResource(R.string.reset_to_body_color),
+                            onClick = {
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterColor(0)))
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterColorNight(0)))
+                            },
+                        )
 
                         TinyClickableSettingItem(
                             title = stringResource(R.string.padding),
@@ -557,10 +602,18 @@ internal fun HeaderFooterPage(
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderColor(color)))
                 }
 
+                COLOR_HEADER_NIGHT -> {
+                    onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderColorNight(color)))
+                }
+
                 COLOR_FOOTER -> {
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterColor(color)))
                 }
 
+                COLOR_FOOTER_NIGHT -> {
+                    onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterColorNight(color)))
+                }
+
                 COLOR_DIVIDER -> {
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipDividerColor(color)))
                 }

+ 11 - 9
app/src/main/java/io/legado/app/ui/book/read/sheet/SystemMenuPage.kt

@@ -89,6 +89,7 @@ private const val COLOR_MENU_CONTAINER_NIGHT = 10
 private const val COLOR_BORDER = 11
 private const val COLOR_BORDER_NIGHT = 12
 private const val COLOR_BLUR_TINT = 13
+private const val COLOR_BLUR_TINT_NIGHT = 14
 
 @Composable
 internal fun SystemMenuPage(
@@ -214,6 +215,7 @@ internal fun SystemMenuPage(
                 COLOR_BORDER -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColor(color)))
                 COLOR_BORDER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColorNight(color)))
                 COLOR_BLUR_TINT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurColor(color)))
+                COLOR_BLUR_TINT_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurColorNight(color)))
             }
             showColorPicker = false
         },
@@ -483,16 +485,16 @@ private fun GlobalMenuTab(
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurAlpha(it.toInt())))
             },
         )
-        TinyClickableSettingItem(
+        TinyColorModeSettingItem(
             title = stringResource(R.string.read_menu_blur_color),
-            onClick = {
-                onShowColorPicker(COLOR_BLUR_TINT, preferences.readMenuBlurColor)
-            },
-            onLongClick = {
-                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurColor(0)))
-            },
-            trailingContent = {
-                TinyColorSwatch(color = preferences.readMenuBlurColor)
+            dayColor = preferences.readMenuBlurColor,
+            nightColor = preferences.readMenuBlurColorNight,
+            onClickColor = { isNight ->
+                if (isNight) {
+                    onShowColorPicker(COLOR_BLUR_TINT_NIGHT, preferences.readMenuBlurColorNight)
+                } else {
+                    onShowColorPicker(COLOR_BLUR_TINT, preferences.readMenuBlurColor)
+                }
             },
         )
     }

+ 35 - 9
app/src/main/java/io/legado/app/ui/book/read/sheet/TextTitleSheet.kt

@@ -60,6 +60,7 @@ import io.legado.app.ui.widget.components.pager.pagerHeight
 import io.legado.app.ui.widget.components.pager.rememberPagerAnimatedHeight
 import io.legado.app.ui.widget.components.pager.rememberPagerFlingPassThroughConnection
 import io.legado.app.ui.widget.components.settingItem.TinyClickableSettingItem
+import io.legado.app.ui.widget.components.settingItem.TinyColorModeSettingItem
 import io.legado.app.ui.widget.components.settingItem.TinyColorSettingItem
 import io.legado.app.ui.widget.components.settingItem.TinyDropdownSettingItem
 import io.legado.app.ui.widget.components.settingItem.TinySliderSettingItem
@@ -71,6 +72,7 @@ import kotlinx.coroutines.launch
 private const val COLOR_TEXT = 1
 private const val COLOR_ACCENT = 2
 private const val COLOR_TITLE = 4
+private const val COLOR_TITLE_NIGHT = 5
 
 @Composable
 fun ReadStyleTextTitleContent(
@@ -436,23 +438,44 @@ internal fun TitleSettingsPage(
             },
         )
 
-        TinyColorSettingItem(
+        TinyColorModeSettingItem(
             title = stringResource(R.string.title_color),
-            colorValue = if (ReadBookConfig.titleColor != 0) {
-                ReadBookConfig.titleColor or 0xFF000000.toInt()
+            dayColor = if (ReadBookConfig.titleColor != 0) {
+                ReadBookConfig.titleColor
             } else {
-                ReadBookConfig.textColor or 0xFF000000.toInt()
+                ReadBookConfig.textColor
             },
-            onClick = {
-                colorPickerId = COLOR_TITLE
-                colorPickerInitial = if (ReadBookConfig.titleColor != 0) {
-                    ReadBookConfig.titleColor or 0xFF000000.toInt()
+            nightColor = if (ReadBookConfig.titleColorNight != 0) {
+                ReadBookConfig.titleColorNight
+            } else {
+                ReadBookConfig.textColorNight
+            },
+            onClickColor = { isNight ->
+                if (isNight) {
+                    colorPickerId = COLOR_TITLE_NIGHT
+                    colorPickerInitial = if (ReadBookConfig.titleColorNight != 0) {
+                        ReadBookConfig.titleColorNight
+                    } else {
+                        ReadBookConfig.textColorNight
+                    }
                 } else {
-                    ReadBookConfig.textColor or 0xFF000000.toInt()
+                    colorPickerId = COLOR_TITLE
+                    colorPickerInitial = if (ReadBookConfig.titleColor != 0) {
+                        ReadBookConfig.titleColor
+                    } else {
+                        ReadBookConfig.textColor
+                    }
                 }
                 showColorPicker = true
             },
         )
+        TinyClickableSettingItem(
+            title = stringResource(R.string.reset_to_body_color),
+            onClick = {
+                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleColor(0)))
+                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleColorNight(0)))
+            },
+        )
 
         // Title font
         TinyClickableSettingItem(
@@ -590,6 +613,9 @@ internal fun TitleSettingsPage(
                 COLOR_TITLE -> {
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleColor(color)))
                 }
+                COLOR_TITLE_NIGHT -> {
+                    onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleColorNight(color)))
+                }
             }
             showColorPicker = false
         },

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -1049,6 +1049,7 @@
     <string name="list_src">List source code</string>
     <string name="title_font_size">Font Size</string>
     <string name="title_color">Title Color</string>
+    <string name="reset_to_body_color">Reset to body text color</string>
     <string name="title_margin_top">Margin Top</string>
     <string name="title_margin_bottom">Margin Bottom</string>
     <string name="show">Show</string>