소스 검색

feat: 优化阅读弹出菜单样式

HapeLee 3 달 전
부모
커밋
ead3d0a821

+ 16 - 8
.github/workflows/auto-release.yml

@@ -19,6 +19,13 @@ on:
     types:
       - completed
   workflow_dispatch:
+  workflow_call:
+    inputs:
+      publish:
+        description: '构建完成后创建 GitHub Release 并发布到 Telegram'
+        required: false
+        type: boolean
+        default: false
 
 permissions:
   contents: write
@@ -82,7 +89,7 @@ jobs:
                 LAST_TAG_FOR_LOG=$(git tag --sort=-committerdate | head -n 2 | tail -n 1)
             fi
           
-          elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then
+          elif [[ ("${{ github.event_name }}" == "push" || "${{ inputs.publish }}" == "true") && "${{ github.ref }}" == "refs/heads/main" ]]; then
             # 标记为测试版 (VERSION_SUFFIX=1 或其他/空),且在 main 分支推送
           
             # 查找匹配当前 CURRENT_VERSION 的上一个 BETA TAG (e.g., 3.26.4-beta.X)
@@ -261,10 +268,8 @@ jobs:
 
   create_release:
     needs: [ prepare, build ]
-    # 发布已迁移到 release.yml;保留该实现一个周期以避免意外删除历史配置。
-    # 仅在所有者的 push 到 main 分支时执行发布
-    if: |
-      false
+    # 只有 Release APK workflow 调用时才发布;普通 Auto Build 仍然只构建产物。
+    if: inputs.publish && github.actor == 'HapeLee' && github.ref == 'refs/heads/main'
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v5
@@ -276,10 +281,9 @@ jobs:
       - name: 下载所有 APK Artifacts
         uses: actions/download-artifact@v4
         with:
-          pattern: '*-apk-*'
+          pattern: '*-apk-release'
           path: artifacts
           merge-multiple: true
-          if-no-artifact-found: error
 
       # 2. 下载 mapping 文件
       - name: 下载 Mapping Artifacts
@@ -325,7 +329,11 @@ jobs:
           LAST_TAG="${{ needs.prepare.outputs.latest_tag }}"
           IS_RELEASE="${{ needs.prepare.outputs.is_release }}"
           
-          COMMIT_LOG=$(git log "$LAST_TAG"..HEAD --pretty=format:"* %s" --no-merges)
+          if [ -n "$LAST_TAG" ] && git rev-parse -q --verify "refs/tags/$LAST_TAG" >/dev/null; then
+            COMMIT_LOG=$(git log "$LAST_TAG"..HEAD --pretty=format:"* %s" --no-merges)
+          else
+            COMMIT_LOG=$(git log -1 --pretty=format:"* %s")
+          fi
           
           if [ -z "$COMMIT_LOG" ]; then
               CONTENT="- 没有新的 Commit 记录."

+ 5 - 147
.github/workflows/release.yml

@@ -2,11 +2,6 @@ name: Release APK
 
 on:
   workflow_dispatch:
-    inputs:
-      build_run_id:
-        description: '成功的 Auto Build workflow run ID'
-        required: true
-        type: string
 
 permissions:
   actions: read
@@ -14,145 +9,8 @@ permissions:
 
 jobs:
   release:
-    # 与原自动发布权限保持一致;请在仓库 Settings 中按需改成你的 GitHub 用户名。
-    if: github.actor == 'HapeLee'
-    runs-on: ubuntu-latest
-    steps:
-      - name: Validate the selected build
-        id: build
-        env:
-          GH_TOKEN: ${{ github.token }}
-          RUN_ID: ${{ inputs.build_run_id }}
-        run: |
-          set -euo pipefail
-          api="https://api.github.com/repos/${GITHUB_REPOSITORY}"
-          run=$(curl --fail-with-body -sS \
-            -H "Authorization: Bearer ${GH_TOKEN}" \
-            -H "Accept: application/vnd.github+json" \
-            "${api}/actions/runs/${RUN_ID}")
-          test "$(jq -r '.name' <<<"${run}")" = "Auto Build"
-          test "$(jq -r '.conclusion' <<<"${run}")" = success
-          test "$(jq -r '.head_branch' <<<"${run}")" = main
-          echo "sha=$(jq -r '.head_sha' <<<"${run}")" >> "$GITHUB_OUTPUT"
-
-      - name: Check out the built commit
-        uses: actions/checkout@v5
-        with:
-          ref: ${{ steps.build.outputs.sha }}
-          fetch-depth: 0
-
-      - name: Download artifacts from the selected build
-        env:
-          GH_TOKEN: ${{ github.token }}
-          RUN_ID: ${{ inputs.build_run_id }}
-        run: |
-          set -euo pipefail
-          api="https://api.github.com/repos/${GITHUB_REPOSITORY}"
-          mkdir artifacts
-          curl --fail-with-body -sS \
-            -H "Authorization: Bearer ${GH_TOKEN}" \
-            -H "Accept: application/vnd.github+json" \
-            "${api}/actions/runs/${RUN_ID}/artifacts?per_page=100" > artifacts.json
-          jq -r '.artifacts[] | select(.expired | not) | select(
-            .name == "universal-apk-release" or
-            .name == "arm64-v8a-apk-release" or
-            .name == "armeabi-v7a-apk-release" or
-            .name == "legado.app.release.mapping" or
-            .name == "release-metadata"
-          ) | .archive_download_url' artifacts.json | while read -r url; do
-            curl --fail-with-body -sSL \
-              -H "Authorization: Bearer ${GH_TOKEN}" \
-              -H "Accept: application/vnd.github+json" \
-              "$url" -o artifact.zip
-            unzip -o artifact.zip -d artifacts
-          done
-          test -f artifacts/release-metadata.env
-
-      - name: Prepare release files and notes
-        id: release
-        run: |
-          set -euo pipefail
-          source artifacts/release-metadata.env
-          test -n "$VERSIONL"
-          mkdir release
-          for apk in artifacts/*.apk; do
-            case "$apk" in
-              *arm64-v8a*) suffix=-arm64-v8a ;;
-              *armeabi-v7a*) suffix=-armeabi-v7a ;;
-              *) suffix= ;;
-            esac
-            mv "$apk" "release/legado-${VERSIONL}${suffix}.apk"
-          done
-          if [ -f artifacts/mapping.txt ]; then mv artifacts/mapping.txt release/; fi
-
-          if [ -n "$LATEST_TAG" ] && git rev-parse -q --verify "refs/tags/$LATEST_TAG" >/dev/null; then
-            notes=$(git log "$LATEST_TAG"..HEAD --pretty=format:'* %s' --no-merges)
-          else
-            notes=$(git log -1 --pretty=format:'* %s')
-          fi
-          [ -n "$notes" ] || notes='- 没有新的 Commit 记录。'
-          {
-            echo 'custom_body<<EOF'
-            if [ "$IS_RELEASE" != true ]; then
-              echo '**此版本为测试版,会存在不稳定问题。**'
-              echo '### [发布页](https://t.me/materado)'
-              echo '### [反馈群组](https://t.me/+Yn1_v5PZqddmMjQ1)'
-              echo
-            fi
-            echo '### 具体更新内容'
-            echo
-            echo "$notes"
-            echo EOF
-          } >> "$GITHUB_OUTPUT"
-          echo "version=$VERSIONL" >> "$GITHUB_OUTPUT"
-          echo "previous_tag=$LATEST_TAG" >> "$GITHUB_OUTPUT"
-          echo "prerelease=$([ "$IS_RELEASE" = true ] && echo false || echo true)" >> "$GITHUB_OUTPUT"
-
-      - name: Create tag at the built commit
-        env:
-          VERSION: ${{ steps.release.outputs.version }}
-        run: |
-          if git rev-parse -q --verify "refs/tags/$VERSION" >/dev/null; then
-            test "$(git rev-list -n 1 "$VERSION")" = "${{ steps.build.outputs.sha }}"
-          else
-            git tag "$VERSION" "${{ steps.build.outputs.sha }}"
-            git push origin "$VERSION"
-          fi
-
-      - name: Generate GitHub release notes
-        id: notes
-        env:
-          GH_TOKEN: ${{ github.token }}
-          VERSION: ${{ steps.release.outputs.version }}
-          SHA: ${{ steps.build.outputs.sha }}
-          PREVIOUS_TAG: ${{ steps.release.outputs.previous_tag }}
-          CUSTOM_BODY: ${{ steps.release.outputs.custom_body }}
-        run: |
-          set -euo pipefail
-          payload=$(jq -n \
-            --arg tag_name "$VERSION" \
-            --arg target_commitish "$SHA" \
-            --arg previous_tag_name "$PREVIOUS_TAG" \
-            '{tag_name: $tag_name, target_commitish: $target_commitish} +
-              (if $previous_tag_name == "" then {} else {previous_tag_name: $previous_tag_name} end)')
-          generated=$(curl --fail-with-body -sS -X POST \
-            -H "Authorization: Bearer ${GH_TOKEN}" \
-            -H "Accept: application/vnd.github+json" \
-            "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
-            -d "$payload" | jq -r .body)
-          {
-            echo 'body<<EOF'
-            echo "$generated"
-            echo
-            echo "$CUSTOM_BODY"
-            echo EOF
-          } >> "$GITHUB_OUTPUT"
-
-      - name: Create GitHub release
-        uses: softprops/action-gh-release@v2
-        with:
-          tag_name: ${{ steps.release.outputs.version }}
-          name: ${{ steps.release.outputs.prerelease == 'true' && format('Pre-release {0}', steps.release.outputs.version) || format('Release {0}', steps.release.outputs.version) }}
-          body: ${{ steps.notes.outputs.body }}
-          prerelease: ${{ steps.release.outputs.prerelease }}
-          files: release/*
+    if: github.actor == 'HapeLee' && github.ref == 'refs/heads/main'
+    uses: ./.github/workflows/auto-release.yml
+    with:
+      publish: true
+    secrets: inherit

+ 11 - 13
app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt

@@ -486,19 +486,17 @@ fun ReadBookRouteScreen(
                 onIntent = viewModel::onIntent,
                 onBack = { controller.closeReadBook() },
             )
-            textMenuState?.let { menuState ->
-                TextActionSelectionMenu(
-                    menuState = menuState,
-                    expandTextMenu = readPreferences.expandTextMenu,
-                    onDismiss = { controller.dismissTextActionMenu() },
-                    onItemClick = { item -> controller.onTextMenuItemClick(item) },
-                    onOpenManage = {
-                        controller.dismissTextActionMenu()
-                        controller.refs?.readView?.cancelSelect()
-                        showSelectMenuConfigSheet = true
-                    }
-                )
-            }
+            TextActionSelectionMenu(
+                menuState = textMenuState,
+                expandTextMenu = readPreferences.expandTextMenu,
+                onDismiss = { controller.dismissTextActionMenu() },
+                onItemClick = { item -> controller.onTextMenuItemClick(item) },
+                onOpenManage = {
+                    controller.dismissTextActionMenu()
+                    controller.refs?.readView?.cancelSelect()
+                    showSelectMenuConfigSheet = true
+                }
+            )
             var configItems by remember { mutableStateOf<List<ActionMenuItem>>(emptyList()) }
             LaunchedEffect(showSelectMenuConfigSheet) {
                 if (showSelectMenuConfigSheet) {

+ 86 - 61
app/src/main/java/io/legado/app/ui/book/read/TextActionSelectionMenu.kt

@@ -1,5 +1,12 @@
 package io.legado.app.ui.book.read
 
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.MutableTransitionState
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.scaleIn
+import androidx.compose.animation.scaleOut
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
@@ -27,6 +34,8 @@ import androidx.compose.material.icons.filled.Settings
 import androidx.compose.material3.Icon
 import androidx.compose.material3.VerticalDivider
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -41,7 +50,6 @@ import androidx.compose.ui.unit.IntRect
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
 import androidx.compose.ui.window.Popup
 import androidx.compose.ui.window.PopupPositionProvider
 import androidx.compose.ui.window.PopupProperties
@@ -58,32 +66,44 @@ enum class MenuMode {
 
 @Composable
 fun TextActionSelectionMenu(
-    menuState: TextMenuState,
+    menuState: TextMenuState?,
     expandTextMenu: Boolean,
     onDismiss: () -> Unit,
     onItemClick: (ActionMenuItem) -> Unit,
     onOpenManage: () -> Unit
 ) {
 
+    var retainedMenuState by remember { mutableStateOf(menuState) }
+    SideEffect {
+        if (menuState != null) retainedMenuState = menuState
+    }
+    val visibilityState = remember { MutableTransitionState(false) }
+    visibilityState.targetState = menuState != null
+    val displayedMenuState = menuState ?: retainedMenuState ?: return
+    if (!visibilityState.currentState && !visibilityState.targetState) return
+
     val localDensity = LocalDensity.current
     val containerSize = LocalWindowInfo.current.containerSize
     val maxMenuWidth = with(localDensity){ containerSize.width.toDp() } - 32.dp
     var mode by remember { mutableStateOf(MenuMode.Quick) }
-    val draftItems = menuState.items
+    LaunchedEffect(menuState) {
+        if (menuState == null) mode = MenuMode.Quick
+    }
+    val draftItems = displayedMenuState.items
     
     val primaryItems = remember(draftItems) { draftItems.filter { it.showState == 0 } }
     val collapsedItems = remember(draftItems) { draftItems.filter { it.showState == 1 } }
     val activeMultiItems = remember(draftItems) { draftItems.filter { it.showState == 0 || it.showState == 1 } }
 
     val density = localDensity.density
-    val positionProvider = remember(menuState, density) {
+    val positionProvider = remember(displayedMenuState, density) {
         TextMenuPositionProvider(
             density = density,
-            startX = menuState.startX,
-            startTopY = menuState.startTopY,
-            startBottomY = menuState.startBottomY,
-            endX = menuState.endX,
-            endBottomY = menuState.endBottomY
+            startX = displayedMenuState.startX,
+            startTopY = displayedMenuState.startTopY,
+            startBottomY = displayedMenuState.startBottomY,
+            endX = displayedMenuState.endX,
+            endBottomY = displayedMenuState.endBottomY
         )
     }
 
@@ -97,43 +117,54 @@ fun TextActionSelectionMenu(
         )
     ) {
 
-        NormalCard(
-            modifier = Modifier.widthIn(max = maxMenuWidth),
-            containerColor = LegadoTheme.colorScheme.surfaceBright,
-            elevation = 6.dp,
-            cornerRadius = 12.dp,
+        AnimatedVisibility(
+            visibleState = visibilityState,
+            enter = fadeIn() + scaleIn(initialScale = 0.9f),
+            exit = fadeOut() + scaleOut(targetScale = 0.9f),
         ) {
-            if (expandTextMenu) {
-                MultiLineMenuView(
-                    items = activeMultiItems,
-                    onItemClick = onItemClick,
-                    onManageClick = {
-                        onDismiss()
-                        onOpenManage()
-                    }
-                )
-            } else {
-                if (mode == MenuMode.Quick) {
-                    QuickMenuView(
-                        items = primaryItems,
-                        hasMore = collapsedItems.isNotEmpty(),
+            NormalCard(
+                modifier = Modifier.widthIn(max = maxMenuWidth),
+                containerColor = LegadoTheme.colorScheme.surfaceBright,
+                elevation = 6.dp,
+                cornerRadius = 12.dp,
+            ) {
+                if (expandTextMenu) {
+                    MultiLineMenuView(
+                        items = activeMultiItems,
                         onItemClick = onItemClick,
-                        onMoreClick = { mode = MenuMode.More },
-                        onSettingsClick = {
+                        onManageClick = {
                             onDismiss()
                             onOpenManage()
                         }
                     )
                 } else {
-                    MoreMenuView(
-                        items = collapsedItems,
-                        onItemClick = onItemClick,
-                        onBack = { mode = MenuMode.Quick },
-                        onManageClick = {
-                            onDismiss()
-                            onOpenManage()
+                    AnimatedContent(
+                        targetState = mode,
+                        label = "TextActionMenuLevel",
+                    ) { targetMode ->
+                        if (targetMode == MenuMode.Quick) {
+                            QuickMenuView(
+                                items = primaryItems,
+                                hasMore = collapsedItems.isNotEmpty(),
+                                onItemClick = onItemClick,
+                                onMoreClick = { mode = MenuMode.More },
+                                onSettingsClick = {
+                                    onDismiss()
+                                    onOpenManage()
+                                }
+                            )
+                        } else {
+                            MoreMenuView(
+                                items = collapsedItems,
+                                onItemClick = onItemClick,
+                                onBack = { mode = MenuMode.Quick },
+                                onManageClick = {
+                                    onDismiss()
+                                    onOpenManage()
+                                }
+                            )
                         }
-                    )
+                    }
                 }
             }
         }
@@ -148,11 +179,10 @@ private fun MultiLineMenuView(
 ) {
     FlowRow(
         modifier = Modifier
-            .padding(all = 8.dp)
             .heightIn(max = 300.dp)
             .verticalScroll(rememberScrollState()),
-        horizontalArrangement = Arrangement.spacedBy(4.dp),
-        verticalArrangement = Arrangement.spacedBy(4.dp)
+        horizontalArrangement = Arrangement.spacedBy(6.dp),
+        verticalArrangement = Arrangement.spacedBy(6.dp)
     ) {
         items.forEach { item ->
             QuickMenuItem(item = item, onClick = { onItemClick(item) })
@@ -161,7 +191,7 @@ private fun MultiLineMenuView(
         Row(
             modifier = Modifier
                 .clickable(onClick = onManageClick)
-                .padding(horizontal = 12.dp, vertical = 8.dp),
+                .padding(horizontal = 14.dp, vertical = 10.dp),
             verticalAlignment = Alignment.CenterVertically
         ) {
             Icon(
@@ -170,10 +200,10 @@ private fun MultiLineMenuView(
                 tint = LegadoTheme.colorScheme.onSurface,
                 modifier = Modifier.size(16.dp)
             )
-            Spacer(modifier = Modifier.width(4.dp))
+            Spacer(modifier = Modifier.width(6.dp))
             AppText(
                 text = stringResource(R.string.edit_menu_items),
-                fontSize = 13.sp,
+                style = LegadoTheme.typography.labelSmallEmphasized
             )
         }
     }
@@ -188,15 +218,11 @@ private fun QuickMenuView(
     onSettingsClick: () -> Unit
 ) {
     Row(
-        modifier = Modifier
-            .wrapContentWidth()
-            .padding(horizontal = 4.dp),
+        modifier = Modifier.wrapContentWidth(),
         verticalAlignment = Alignment.CenterVertically
     ) {
         LazyRow(
-            modifier = Modifier
-                .weight(1f, fill = false)
-                .padding(vertical = 6.dp),
+            modifier = Modifier.weight(1f, fill = false),
             verticalAlignment = Alignment.CenterVertically,
         ) {
             items(items, key = { it.uniqueId }) { item ->
@@ -214,7 +240,7 @@ private fun QuickMenuView(
         Box(
             modifier = Modifier
                 .clickable(onClick = if (hasMore) onMoreClick else onSettingsClick)
-                .padding(horizontal = 10.dp, vertical = 8.dp),
+                .padding(horizontal = 16.dp, vertical = 12.dp),
             contentAlignment = Alignment.Center
         ) {
             Icon(
@@ -235,7 +261,7 @@ private fun QuickMenuItem(
     Row(
         modifier = Modifier
             .clickable(onClick = onClick)
-            .padding(horizontal = 10.dp, vertical = 8.dp),
+            .padding(horizontal = 16.dp, vertical = 12.dp),
         verticalAlignment = Alignment.CenterVertically
     ) {
         if (item.iconDrawable != null) {
@@ -246,11 +272,11 @@ private fun QuickMenuItem(
                     .size(16.dp)
             )
 
-            Spacer(modifier = Modifier.width(4.dp))
+            Spacer(modifier = Modifier.width(12.dp))
         }
         AppText(
             text = item.title,
-            fontSize = 13.sp,
+            style = LegadoTheme.typography.labelMedium,
             maxLines = 1
         )
     }
@@ -268,13 +294,12 @@ private fun MoreMenuView(
     Column(
         modifier = Modifier
             .width(IntrinsicSize.Max)
-            .padding(vertical = 4.dp, horizontal = 10.dp)
     ) {
         Box(
             modifier = Modifier
                 .fillMaxWidth()
                 .clickable(onClick = onBack)
-                .padding(vertical = 8.dp),
+                .padding(horizontal = 16.dp, vertical = 12.dp),
             contentAlignment = Alignment.CenterStart
         ) {
             Icon(
@@ -300,7 +325,7 @@ private fun MoreMenuView(
             modifier = Modifier
                 .fillMaxWidth()
                 .clickable(onClick = onManageClick)
-                .padding(vertical = 8.dp),
+                .padding(horizontal = 16.dp, vertical = 12.dp),
             verticalAlignment = Alignment.CenterVertically
         ) {
             Icon(
@@ -313,7 +338,7 @@ private fun MoreMenuView(
             Spacer(modifier = Modifier.width(8.dp))
             AppText(
                 text = stringResource(R.string.edit_menu_items),
-                fontSize = 13.sp,
+                style = LegadoTheme.typography.labelMedium
             )
         }
     }
@@ -328,7 +353,7 @@ private fun MoreMenuItem(
         modifier = Modifier
             .fillMaxWidth()
             .clickable(onClick = onClick)
-            .padding(vertical = 8.dp),
+            .padding(horizontal = 16.dp, vertical = 12.dp),
         verticalAlignment = Alignment.CenterVertically
     ) {
         if (item.iconDrawable != null) {
@@ -338,11 +363,11 @@ private fun MoreMenuItem(
                 modifier = Modifier
                     .size(16.dp)
             )
-            Spacer(modifier = Modifier.width(8.dp))
+            Spacer(modifier = Modifier.width(12.dp))
         }
         AppText(
             text = item.title,
-            fontSize = 13.sp,
+            style = LegadoTheme.typography.labelMedium
         )
     }
 }

+ 26 - 69
app/src/main/java/io/legado/app/ui/book/read/sheet/TextSelectMenuConfigSheet.kt

@@ -4,7 +4,6 @@ import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -25,9 +24,9 @@ import androidx.compose.material.icons.filled.Add
 import androidx.compose.material.icons.filled.KeyboardArrowDown
 import androidx.compose.material.icons.filled.Menu
 import androidx.compose.material.icons.filled.Remove
+import androidx.compose.material.icons.filled.Save
 import androidx.compose.material.icons.filled.VisibilityOff
 import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.HorizontalDivider
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.runtime.Composable
@@ -41,19 +40,18 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.rotate
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.ui.book.read.ActionMenuItem
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.TinySwitch
-import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
+import io.legado.app.ui.widget.components.button.series.SmallTonalButton
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.TinyClickableSettingItem
 import io.legado.app.ui.widget.components.settingItem.TinySettingItem
+import io.legado.app.ui.widget.components.settingItem.TinySwitchSettingItem
 import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
@@ -115,6 +113,15 @@ fun TextSelectMenuConfigSheet(
         show = show,
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.edit_select_menu),
+        endAction = {
+            SmallTonalButton(
+                onClick = {
+                    onSaved(draftItems)
+                    onDismissRequest()
+                },
+                icon = Icons.Default.Save
+            )
+        }
     ) {
         Column(
             modifier = Modifier
@@ -126,64 +133,25 @@ fun TextSelectMenuConfigSheet(
                 state = lazyListState,
                 verticalArrangement = Arrangement.spacedBy(4.dp),
                 modifier = Modifier
-                    .weight(1f)
-                    .padding(horizontal = 16.dp),
+                    .weight(1f),
             ) {
                 item {
-                    NormalCard(
-                        cornerRadius = 12.dp,
-                        containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
+                    Column(
                         modifier = Modifier
-                            .fillMaxWidth()
                             .animateItem()
-                            .padding(top = 12.dp, bottom = 4.dp)
+                            .padding(top = 12.dp),
+                        verticalArrangement = Arrangement.spacedBy(4.dp)
                     ) {
-                        Column {
-                            Row(
-                                modifier = Modifier
-                                    .fillMaxWidth()
-                                    .clickable { onExpandTextMenuChange(!expandTextMenu) }
-                                    .padding(horizontal = 16.dp, vertical = 12.dp),
-                                verticalAlignment = Alignment.CenterVertically
-                            ) {
-                                AppText(
-                                    text = stringResource(R.string.expand_text_menu),
-                                    style = LegadoTheme.typography.titleSmallEmphasized,
-                                    modifier = Modifier.weight(1f),
-                                    maxLines = 1,
-                                    overflow = TextOverflow.Ellipsis
-                                )
-                                TinySwitch(
-                                    checked = expandTextMenu,
-                                    onCheckedChange = onExpandTextMenuChange
-                                )
-                            }
-
-                            HorizontalDivider(
-                                modifier = Modifier.padding(horizontal = 16.dp),
-                                color = LegadoTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)
-                            )
-
-                            Row(
-                                modifier = Modifier
-                                    .fillMaxWidth()
-                                    .clickable { onShowSelectMenuIconChange(!showSelectMenuIcon) }
-                                    .padding(horizontal = 16.dp, vertical = 12.dp),
-                                verticalAlignment = Alignment.CenterVertically
-                            ) {
-                                AppText(
-                                    text = stringResource(R.string.show_select_menu_icon),
-                                    style = LegadoTheme.typography.titleSmallEmphasized,
-                                    modifier = Modifier.weight(1f),
-                                    maxLines = 1,
-                                    overflow = TextOverflow.Ellipsis
-                                )
-                                TinySwitch(
-                                    checked = showSelectMenuIcon,
-                                    onCheckedChange = onShowSelectMenuIconChange
-                                )
-                            }
-                        }
+                        TinySwitchSettingItem(
+                            title = stringResource(R.string.expand_text_menu),
+                            checked = expandTextMenu,
+                            onCheckedChange = onExpandTextMenuChange
+                        )
+                        TinySwitchSettingItem(
+                            title = stringResource(R.string.show_select_menu_icon),
+                            checked = showSelectMenuIcon,
+                            onCheckedChange = onShowSelectMenuIconChange
+                        )
                     }
                 }
 
@@ -313,17 +281,6 @@ fun TextSelectMenuConfigSheet(
                     }
                 }
             }
-
-            ConfirmDismissButtonsRow(
-                onDismiss = onDismissRequest,
-                onConfirm = {
-                    onSaved(draftItems)
-                    onDismissRequest()
-                },
-                dismissText = stringResource(R.string.cancel),
-                confirmText = stringResource(R.string.action_save),
-                modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp),
-            )
         }
     }
 }