HapeLee 3 месяцев назад
Родитель
Сommit
262a3acfe1

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

@@ -346,6 +346,7 @@ object PreferKey {
     const val readMenuTopBarBlurMode = "readMenuTopBarBlurMode"
     const val readMenuBottomBarBlurMode = "readMenuBottomBarBlurMode"
     const val readMenuTopBarLiquidGlassButtons = "readMenuTopBarLiquidGlassButtons"
+    const val readMenuTopBarMergeButtons = "readMenuTopBarMergeButtons"
     const val readMenuTopBarTitleCapsule = "readMenuTopBarTitleCapsule"
     const val readMenuBottomBarLiquidGlassButtons = "readMenuBottomBarLiquidGlassButtons"
     const val readMenuFloatingIconLiquidGlass = "readMenuFloatingIconLiquidGlass"

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

@@ -260,6 +260,9 @@ class ReadSettingsRepository(
     suspend fun setReadMenuTopBarLiquidGlassButtons(value: Boolean) =
         settingsRepository.putBoolean(PreferKey.readMenuTopBarLiquidGlassButtons, value)
 
+    suspend fun setReadMenuTopBarMergeButtons(value: Boolean) =
+        settingsRepository.putBoolean(PreferKey.readMenuTopBarMergeButtons, value)
+
     suspend fun setReadMenuTopBarTitleCapsule(value: Boolean) =
         settingsRepository.putBoolean(PreferKey.readMenuTopBarTitleCapsule, value)
 
@@ -417,6 +420,7 @@ class ReadSettingsRepository(
             readMenuTopBarBlurMode = compatDsValue(Keys.ReadMenuTopBarBlurMode, ReadMenuBlurMode.None),
             readMenuBottomBarBlurMode = compatDsValue(Keys.ReadMenuBottomBarBlurMode, ReadMenuBlurMode.None),
             readMenuTopBarLiquidGlassButtons = compatDsValue(Keys.ReadMenuTopBarLiquidGlassButtons, false),
+            readMenuTopBarMergeButtons = compatDsValue(Keys.ReadMenuTopBarMergeButtons, false),
             readMenuTopBarTitleCapsule = compatDsValue(Keys.ReadMenuTopBarTitleCapsule, false),
             readMenuBottomBarLiquidGlassButtons = compatDsValue(Keys.ReadMenuBottomBarLiquidGlassButtons, false),
             readMenuFloatingIconLiquidGlass = compatDsValue(
@@ -533,6 +537,8 @@ class ReadSettingsRepository(
         val ReadMenuBottomBarBlurMode = intPreferencesKey(PreferKey.readMenuBottomBarBlurMode)
         val ReadMenuTopBarLiquidGlassButtons =
             booleanPreferencesKey(PreferKey.readMenuTopBarLiquidGlassButtons)
+        val ReadMenuTopBarMergeButtons =
+            booleanPreferencesKey(PreferKey.readMenuTopBarMergeButtons)
         val ReadMenuTopBarTitleCapsule =
             booleanPreferencesKey(PreferKey.readMenuTopBarTitleCapsule)
         val ReadMenuBottomBarLiquidGlassButtons =
@@ -656,6 +662,7 @@ internal fun ReadSettings.toGatewayPrefMap(): Map<String, Any?> = mapOf(
     PreferKey.readMenuTopBarBlurMode to readMenuTopBarBlurMode,
     PreferKey.readMenuBottomBarBlurMode to readMenuBottomBarBlurMode,
     PreferKey.readMenuTopBarLiquidGlassButtons to readMenuTopBarLiquidGlassButtons,
+    PreferKey.readMenuTopBarMergeButtons to readMenuTopBarMergeButtons,
     PreferKey.readMenuTopBarTitleCapsule to readMenuTopBarTitleCapsule,
     PreferKey.readMenuBottomBarLiquidGlassButtons to readMenuBottomBarLiquidGlassButtons,
     PreferKey.readMenuFloatingIconLiquidGlass to readMenuFloatingIconLiquidGlass,

+ 1 - 0
app/src/main/java/io/legado/app/domain/model/settings/ReadSettings.kt

@@ -87,6 +87,7 @@ data class ReadSettings(
     val readMenuTopBarBlurMode: Int = ReadMenuBlurMode.None,
     val readMenuBottomBarBlurMode: Int = ReadMenuBlurMode.None,
     val readMenuTopBarLiquidGlassButtons: Boolean = false,
+    val readMenuTopBarMergeButtons: Boolean = false,
     val readMenuTopBarTitleCapsule: Boolean = false,
     val readMenuBottomBarLiquidGlassButtons: Boolean = false,
     val readMenuFloatingIconLiquidGlass: Boolean = false,

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

@@ -79,6 +79,7 @@ object ReadBookConfig {
     val titleBarCompact get() = readSettings.titleBarCompact
     val readMenuFloatingBottomBar get() = readSettings.readMenuFloatingBottomBar
     val readMenuTopBarLiquidGlassButtons get() = readSettings.readMenuTopBarLiquidGlassButtons
+    val readMenuTopBarMergeButtons get() = readSettings.readMenuTopBarMergeButtons
     val readMenuTopBarTitleCapsule get() = readSettings.readMenuTopBarTitleCapsule
     val readMenuBottomBarLiquidGlassButtons get() = readSettings.readMenuBottomBarLiquidGlassButtons
     val readMenuFloatingIconLiquidGlass get() = readSettings.readMenuFloatingIconLiquidGlass

+ 1 - 0
app/src/main/java/io/legado/app/help/storage/BackupConfig.kt

@@ -223,6 +223,7 @@ object BackupConfig {
         PreferKey.readMenuTopBarBlurMode,
         PreferKey.readMenuBottomBarBlurMode,
         PreferKey.readMenuTopBarLiquidGlassButtons,
+        PreferKey.readMenuTopBarMergeButtons,
         PreferKey.readMenuTopBarTitleCapsule,
         PreferKey.readMenuBottomBarLiquidGlassButtons,
         PreferKey.readMenuFloatingIconLiquidGlass,

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt

@@ -120,6 +120,7 @@ import io.legado.app.ui.widget.components.topbar.GlassTopAppBarScrollBehavior
 import io.legado.app.ui.widget.components.topbar.M3GlassScrollBehavior
 import io.legado.app.ui.widget.components.topbar.MiuixGlassScrollBehavior
 import io.legado.app.ui.widget.components.topbar.TopBarActionButton
+import io.legado.app.ui.widget.components.topbar.TopBarActionsRow
 import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
 import io.legado.app.ui.widget.components.variable.VariableEditorSheet
 import kotlinx.collections.immutable.ImmutableList
@@ -538,9 +539,7 @@ private fun BookInfoTransparentTopAppBar(
             },
             actions = {
                 Box(modifier = Modifier.padding(end = 12.dp)) {
-                    Row(
-                        horizontalArrangement = Arrangement.spacedBy(8.dp)
-                    ) {
+                    TopBarActionsRow {
                         BookInfoTopBarActions(
                             state = state,
                             onMenuAction = onMenuAction,

+ 6 - 4
app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt

@@ -23,10 +23,10 @@ import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.automirrored.outlined.FormatListBulleted
-import androidx.compose.material.icons.filled.Book
-import androidx.compose.material.icons.filled.Group
 import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.Book
 import androidx.compose.material.icons.filled.FolderOpen
+import androidx.compose.material.icons.filled.Group
 import androidx.compose.material.icons.filled.ImageSearch
 import androidx.compose.material.icons.filled.Replay
 import androidx.compose.material.icons.filled.Save
@@ -72,6 +72,7 @@ import io.legado.app.ui.widget.components.text.AnimatedTextLine
 import io.legado.app.ui.widget.components.text.AppText
 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.TopBarActionButton
 import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
 import io.legado.app.utils.SelectImageContract
 import io.legado.app.utils.launch
@@ -104,9 +105,10 @@ fun BookInfoEditScreen(
                     )
                 },
                 actions = {
-                    TopBarNavigationButton(
+                    TopBarActionButton(
                         onClick = { viewModel.save(onSave) },
-                        imageVector = Icons.Default.Save
+                        imageVector = Icons.Default.Save,
+                        contentDescription = stringResource(R.string.save)
                     )
                 },
                 scrollBehavior = scrollBehavior

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

@@ -355,6 +355,7 @@ data class ReadMenuConfig(
     val readMenuTopBarBlurMode: Int = ReadMenuBlurMode.None,
     val readMenuBottomBarBlurMode: Int = ReadMenuBlurMode.None,
     val readMenuTopBarLiquidGlassButtons: Boolean = false,
+    val readMenuTopBarMergeButtons: Boolean = false,
     val readMenuTopBarTitleCapsule: Boolean = false,
     val readMenuBottomBarLiquidGlassButtons: Boolean = false,
     val readMenuFloatingIconLiquidGlass: Boolean = false,
@@ -1397,6 +1398,10 @@ sealed interface ConfigUpdate {
     data class MenuTopBarLiquidGlassButtons(val value: Boolean) : ConfigUpdate {
         override val actions = emptySet<ConfigUpdateAction>()
     }
+
+    data class MenuTopBarMergeButtons(val value: Boolean) : ConfigUpdate {
+        override val actions = emptySet<ConfigUpdateAction>()
+    }
     data class MenuTopBarTitleCapsule(val value: Boolean) : ConfigUpdate {
         override val actions = emptySet<ConfigUpdateAction>()
     }

+ 43 - 21
app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBarTitle.kt

@@ -222,12 +222,16 @@ internal fun MenuTitleBar(
             }
 
             // Right group: actions
-            if (readMenuTopBarButtonLiquidGlassEnabled(backdrop, state.menuConfig)) {
+            if (state.menuConfig.readMenuTopBarMergeButtons) {
                 MenuTitleBarMergedGlassButton(
                     state = state,
                     colors = colors,
                     onIntent = onIntent,
                     backdrop = backdrop,
+                    glassEnabled = readMenuTopBarButtonLiquidGlassEnabled(
+                        backdrop,
+                        state.menuConfig
+                    ),
                 )
             } else {
                 val compact = state.menuConfig.titleBarCompact
@@ -735,6 +739,7 @@ private fun MenuTitleBarMergedGlassButton(
     colors: ReadMenuColors,
     onIntent: (ReadBookIntent) -> Unit,
     backdrop: Backdrop?,
+    glassEnabled: Boolean,
 ) {
     var sourceExpanded by remember { mutableStateOf(false) }
     var refreshExpanded by remember { mutableStateOf(false) }
@@ -742,34 +747,51 @@ private fun MenuTitleBarMergedGlassButton(
     val pillShape = RoundedCornerShape(50)
     val tint = LegadoTheme.colorScheme.onSurfaceVariant
     val compact = state.menuConfig.titleBarCompact
+    val iconStyle = state.menuConfig.titleBarIconStyle
 
     Box {
         Row(
             modifier = Modifier
                 .height(40.dp)
-                .readMenuLiquidGlass(
-                    backdrop = backdrop,
-                    colors = colors,
-                    shape = pillShape,
-                    useTopBarStyle = true,
-                    useLens = true,
-                    blurRadius = 32.dp,
-                    interactive = true,
-                    menuConfig = state.menuConfig,
-                )
                 .then(
-                    if (state.menuConfig.readMenuBorderWidth > 0 &&
-                        state.menuConfig.readMenuTopBarTitleCapsule
-                    ) {
-                        Modifier.border(
-                            BorderStroke(
-                                state.menuConfig.readMenuBorderWidth.dp,
-                                Color(readMenuBorderColor(state.menuConfig)),
-                            ),
-                            pillShape,
+                    if (glassEnabled) {
+                        Modifier.readMenuLiquidGlass(
+                            backdrop = backdrop,
+                            colors = colors,
+                            shape = pillShape,
+                            useTopBarStyle = true,
+                            useLens = true,
+                            blurRadius = 32.dp,
+                            interactive = true,
+                            menuConfig = state.menuConfig,
                         )
                     } else {
-                        Modifier
+                        val containerColor = when (iconStyle) {
+                            1 -> LegadoTheme.colorScheme.surfaceContainerLow
+                            else -> Color.Transparent
+                        }
+                        Modifier.background(containerColor, pillShape)
+                    }
+                )
+                .then(
+                    when {
+                        state.menuConfig.readMenuBorderWidth > 0 &&
+                                state.menuConfig.readMenuTopBarTitleCapsule ->
+                            Modifier.border(
+                                BorderStroke(
+                                    state.menuConfig.readMenuBorderWidth.dp,
+                                    Color(readMenuBorderColor(state.menuConfig)),
+                                ),
+                                pillShape,
+                            )
+
+                        !glassEnabled && iconStyle == 2 ->
+                            Modifier.border(
+                                BorderStroke(1.dp, tint.copy(alpha = 0.45f)),
+                                pillShape,
+                            )
+
+                        else -> Modifier
                     }
                 ),
             verticalAlignment = Alignment.CenterVertically,

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

@@ -1908,6 +1908,7 @@ class ReadBookViewModel(
                 readMenuTopBarBlurMode = ReadBookConfig.readMenuTopBarBlurMode,
                 readMenuBottomBarBlurMode = ReadBookConfig.readMenuBottomBarBlurMode,
                 readMenuTopBarLiquidGlassButtons = ReadBookConfig.readMenuTopBarLiquidGlassButtons,
+                readMenuTopBarMergeButtons = ReadBookConfig.readMenuTopBarMergeButtons,
                 readMenuTopBarTitleCapsule = ReadBookConfig.readMenuTopBarTitleCapsule,
                 readMenuBottomBarLiquidGlassButtons = ReadBookConfig.readMenuBottomBarLiquidGlassButtons,
                 readMenuFloatingIconLiquidGlass = ReadBookConfig.readMenuFloatingIconLiquidGlass,

+ 10 - 1
app/src/main/java/io/legado/app/ui/book/read/ReadConfigUpdateDelegate.kt

@@ -3,11 +3,11 @@ package io.legado.app.ui.book.read
 import io.legado.app.constant.EventBus
 import io.legado.app.constant.PreferKey
 import io.legado.app.constant.ReadMenuBlurMode
-import io.legado.app.domain.gateway.ReadStyleGateway
 import io.legado.app.data.repository.ReadSettingsRepository
 import io.legado.app.domain.gateway.ReadStyleBooleanKey
 import io.legado.app.domain.gateway.ReadStyleColorKey
 import io.legado.app.domain.gateway.ReadStyleFloatKey
+import io.legado.app.domain.gateway.ReadStyleGateway
 import io.legado.app.domain.gateway.ReadStyleIntKey
 import io.legado.app.domain.gateway.ReadStyleMutation
 import io.legado.app.domain.gateway.ReadStyleStringKey
@@ -353,6 +353,15 @@ class ReadConfigUpdateDelegate(
                 }
             }
 
+            is ConfigUpdate.MenuTopBarMergeButtons -> {
+                scope.launch {
+                    readSettingsRepository.setReadMenuTopBarMergeButtons(update.value)
+                }
+                host.updateMenuConfig {
+                    it.copy(readMenuTopBarMergeButtons = update.value)
+                }
+            }
+
             is ConfigUpdate.MenuTopBarTitleCapsule -> {
                 scope.launch {
                     readSettingsRepository.setReadMenuTopBarTitleCapsule(update.value)

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

@@ -864,6 +864,18 @@ private fun TopBarTab(
                 )
             },
         )
+        TinySwitchSettingItem(
+            title = stringResource(R.string.read_menu_top_bar_merge_buttons),
+            description = stringResource(R.string.read_menu_top_bar_merge_buttons_summary),
+            checked = preferences.readMenuTopBarMergeButtons,
+            onCheckedChange = {
+                onIntent(
+                    ReadBookIntent.UpdateConfig(
+                        ConfigUpdate.MenuTopBarMergeButtons(it)
+                    )
+                )
+            },
+        )
     }
 }
 

+ 16 - 20
app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt

@@ -174,27 +174,23 @@ fun SearchContentScreen(
                     } else "搜索内容",
                     navigationIcon = { TopBarNavigationButton(onClick = onBack) },
                     actions = {
-                        Row(
-                            horizontalArrangement = Arrangement.spacedBy(4.dp)
-                        ) {
-                            TopBarAnimatedActionButton(
-                                checked = replaceEnabled,
-                                onCheckedChange = { onIntent(SearchContentIntent.ToggleReplace(it)) },
-                                iconChecked = Icons.Default.FindReplace,
-                                iconUnchecked = Icons.Default.FindReplace,
-                                activeText = "替换开启",
-                                inactiveText = "替换关闭"
-                            )
+                        TopBarAnimatedActionButton(
+                            checked = replaceEnabled,
+                            onCheckedChange = { onIntent(SearchContentIntent.ToggleReplace(it)) },
+                            iconChecked = Icons.Default.FindReplace,
+                            iconUnchecked = Icons.Default.FindReplace,
+                            activeText = "替换开启",
+                            inactiveText = "替换关闭"
+                        )
 
-                            TopBarAnimatedActionButton(
-                                checked = regexReplace,
-                                onCheckedChange = { onIntent(SearchContentIntent.ToggleRegex(it)) },
-                                iconChecked = Icons.Default.Code,
-                                iconUnchecked = Icons.Default.Code,
-                                activeText = "正则开启",
-                                inactiveText = "正则关闭"
-                            )
-                        }
+                        TopBarAnimatedActionButton(
+                            checked = regexReplace,
+                            onCheckedChange = { onIntent(SearchContentIntent.ToggleRegex(it)) },
+                            iconChecked = Icons.Default.Code,
+                            iconUnchecked = Icons.Default.Code,
+                            activeText = "正则开启",
+                            inactiveText = "正则关闭"
+                        )
                     },
                     scrollBehavior = scrollBehavior
                 )

+ 8 - 1
app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassTopAppBar.kt

@@ -1,10 +1,12 @@
 package io.legado.app.ui.widget.components.topbar
 
 import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ExperimentalLayoutApi
 import androidx.compose.foundation.layout.RowScope
 import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.statusBarsIgnoringVisibility
 import androidx.compose.foundation.layout.windowInsetsPadding
 import androidx.compose.material3.ExperimentalMaterial3Api
@@ -16,6 +18,7 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.LocalHazeState
 import io.legado.app.ui.theme.ThemeResolver
@@ -72,7 +75,11 @@ fun GlassTopAppBar(
                     )
                 },
                 navigationIcon = navigationIcon,
-                actions = { TopBarActionsRow { actions() } },
+                actions = {
+                    Box(modifier = Modifier.padding(end = 12.dp)) {
+                        TopBarActionsRow { actions() }
+                    }
+                },
                 colors = TopAppBarDefaults.topAppBarColors(
                     containerColor = Color.Transparent,
                     scrolledContainerColor = Color.Transparent

+ 2 - 0
app/src/main/res/values-zh-rCN/strings.xml

@@ -2243,6 +2243,8 @@
     <string name="read_menu_bar_blur_style">着色样式</string>
     <string name="read_menu_blur_style_progressive">渐变</string>
     <string name="read_menu_top_bar_liquid_glass_buttons_summary">需要 Android 13 及以上系统</string>
+    <string name="read_menu_top_bar_merge_buttons">合并顶栏按钮</string>
+    <string name="read_menu_top_bar_merge_buttons_summary">将顶栏操作按钮合并为胶囊</string>
     <string name="read_menu_blur_radius">模糊半径</string>
     <string name="read_menu_blur_radius_summary">模糊半径越大,系统运行越卡顿</string>
     <string name="read_menu_blur_alpha">菜单不透明度</string>

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

@@ -2270,6 +2270,8 @@
     <string name="read_menu_blur_style_solid">Fill</string>
     <string name="read_menu_blur_style_progressive">Gradient</string>
     <string name="read_menu_top_bar_liquid_glass_buttons_summary">Apply liquid glass to title bar action buttons. Requires Android 13+</string>
+    <string name="read_menu_top_bar_merge_buttons">Merge Top Bar Buttons</string>
+    <string name="read_menu_top_bar_merge_buttons_summary">Merge top bar action buttons into a capsule</string>
     <string name="read_menu_blur_radius">Blur radius</string>
     <string name="read_menu_blur_radius_summary">Higher radius may reduce performance</string>
     <string name="read_menu_blur_alpha">Menu opacity</string>

+ 3 - 1
app/src/test/java/io/legado/app/data/repository/ReadSettingsMappingTest.kt

@@ -18,7 +18,7 @@ class ReadSettingsMappingTest {
         val actualKeys = ReadSettings().toGatewayPrefMap().keys
         val expectedKeys = ReadSettings().expectedGatewayPrefMap().keys
 
-        assertEquals(105, actualKeys.size)
+        assertEquals(106, actualKeys.size)
         assertEquals(expectedKeys, actualKeys)
     }
 
@@ -166,6 +166,7 @@ private fun readSettingsMappingSamples(): List<ReadSettings> {
         readMenuTopBarBlurMode = 1037,
         readMenuBottomBarBlurMode = 1038,
         readMenuTopBarLiquidGlassButtons = true,
+        readMenuTopBarMergeButtons = true,
         readMenuTopBarTitleCapsule = true,
         readMenuBottomBarLiquidGlassButtons = true,
         readMenuTopBarBlurStyle = 1042,
@@ -303,6 +304,7 @@ private fun ReadSettings.expectedGatewayPrefMap(): Map<String, Any?> = mapOf(
     PreferKey.readMenuTopBarBlurMode to readMenuTopBarBlurMode,
     PreferKey.readMenuBottomBarBlurMode to readMenuBottomBarBlurMode,
     PreferKey.readMenuTopBarLiquidGlassButtons to readMenuTopBarLiquidGlassButtons,
+    PreferKey.readMenuTopBarMergeButtons to readMenuTopBarMergeButtons,
     PreferKey.readMenuTopBarTitleCapsule to readMenuTopBarTitleCapsule,
     PreferKey.readMenuBottomBarLiquidGlassButtons to readMenuBottomBarLiquidGlassButtons,
     PreferKey.readMenuFloatingIconLiquidGlass to readMenuFloatingIconLiquidGlass,