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

feat: 小容器背景喵喵喵

HapeLee 3 месяцев назад
Родитель
Сommit
cf3e55c194
100 измененных файлов с 1174 добавлено и 1318 удалено
  1. 23 0
      app/src/main/java/io/legado/app/data/repository/ThemePackageSettingsRepository.kt
  2. 7 0
      app/src/main/java/io/legado/app/domain/model/settings/ThemeExportData.kt
  3. 7 0
      app/src/main/java/io/legado/app/domain/model/settings/ThemeSettings.kt
  4. 21 0
      app/src/main/java/io/legado/app/help/config/ThemeImportExport.kt
  5. 77 9
      app/src/main/java/io/legado/app/help/config/ThemePackageManager.kt
  6. 2 10
      app/src/main/java/io/legado/app/ui/about/AboutScreen.kt
  7. 3 4
      app/src/main/java/io/legado/app/ui/about/AboutSheets.kt
  8. 3 3
      app/src/main/java/io/legado/app/ui/about/CrashReportScreen.kt
  9. 6 14
      app/src/main/java/io/legado/app/ui/about/MiuixAboutScreen.kt
  10. 10 15
      app/src/main/java/io/legado/app/ui/ai/chat/AiChatScreen.kt
  11. 5 10
      app/src/main/java/io/legado/app/ui/ai/chat/AiGeneratedMessageContent.kt
  12. 5 3
      app/src/main/java/io/legado/app/ui/ai/chat/AiReasoningCard.kt
  13. 3 5
      app/src/main/java/io/legado/app/ui/ai/chat/AiThinkingCard.kt
  14. 10 12
      app/src/main/java/io/legado/app/ui/ai/chat/AiThinkingStepsCard.kt
  15. 4 10
      app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt
  16. 5 8
      app/src/main/java/io/legado/app/ui/book/cache/manage/BookCacheManageScreen.kt
  17. 1 2
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceMigrationOptionsSheet.kt
  18. 2 3
      app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt
  19. 2 9
      app/src/main/java/io/legado/app/ui/book/import/local/ImportBookScreen.kt
  20. 6 6
      app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt
  21. 2 6
      app/src/main/java/io/legado/app/ui/book/info/BookInfoReadRecordSheet.kt
  22. 23 36
      app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt
  23. 3 6
      app/src/main/java/io/legado/app/ui/book/info/BookInfoSheets.kt
  24. 4 6
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt
  25. 7 8
      app/src/main/java/io/legado/app/ui/book/knowledge/BookCharacterDetailScreen.kt
  26. 9 15
      app/src/main/java/io/legado/app/ui/book/knowledge/BookCharacterListScreen.kt
  27. 3 4
      app/src/main/java/io/legado/app/ui/book/knowledge/BookCharacterNetworkScreen.kt
  28. 1 2
      app/src/main/java/io/legado/app/ui/book/knowledge/BookEventDetailScreen.kt
  29. 1 2
      app/src/main/java/io/legado/app/ui/book/knowledge/BookEventListScreen.kt
  30. 2 3
      app/src/main/java/io/legado/app/ui/book/knowledge/BookKnowledgeDetailScreen.kt
  31. 1 2
      app/src/main/java/io/legado/app/ui/book/knowledge/BookKnowledgeListScreen.kt
  32. 1 2
      app/src/main/java/io/legado/app/ui/book/knowledge/CharacterAvatarCropDialog.kt
  33. 2 3
      app/src/main/java/io/legado/app/ui/book/knowledge/KnowledgeSharedComponents.kt
  34. 12 22
      app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageScreen.kt
  35. 29 25
      app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt
  36. 2 3
      app/src/main/java/io/legado/app/ui/book/read/TextActionSelectionMenu.kt
  37. 5 8
      app/src/main/java/io/legado/app/ui/book/read/sheet/AiRewritePresetConfigSheet.kt
  38. 3 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/AiTextCleanSheet.kt
  39. 7 12
      app/src/main/java/io/legado/app/ui/book/read/sheet/AiTextRewriteSheet.kt
  40. 7 6
      app/src/main/java/io/legado/app/ui/book/read/sheet/AutoReadSheet.kt
  41. 7 5
      app/src/main/java/io/legado/app/ui/book/read/sheet/BgTextConfigSheet.kt
  42. 1 2
      app/src/main/java/io/legado/app/ui/book/read/sheet/ChangeChapterSourceSheet.kt
  43. 3 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/ChapterSummarySheet.kt
  44. 1 3
      app/src/main/java/io/legado/app/ui/book/read/sheet/CharsetConfigSheet.kt
  45. 4 6
      app/src/main/java/io/legado/app/ui/book/read/sheet/ClickActionConfigSheet.kt
  46. 3 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/ContentEditSheet.kt
  47. 4 6
      app/src/main/java/io/legado/app/ui/book/read/sheet/ContentProcessesSheet.kt
  48. 1 2
      app/src/main/java/io/legado/app/ui/book/read/sheet/DownloadSheet.kt
  49. 3 6
      app/src/main/java/io/legado/app/ui/book/read/sheet/EffectiveReplacesSheet.kt
  50. 3 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/EyeProtectionConfigSheet.kt
  51. 3 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/FloatingBarIconConfigSheet.kt
  52. 5 10
      app/src/main/java/io/legado/app/ui/book/read/sheet/GlobalThemePage.kt
  53. 293 414
      app/src/main/java/io/legado/app/ui/book/read/sheet/HeaderFooterPage.kt
  54. 3 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/HighlightRuleConfigSheet.kt
  55. 20 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/HighlightRuleEditSheet.kt
  56. 8 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/MoreConfigSheet.kt
  57. 3 6
      app/src/main/java/io/legado/app/ui/book/read/sheet/PaddingConfigSheet.kt
  58. 6 8
      app/src/main/java/io/legado/app/ui/book/read/sheet/PageKeyConfigSheet.kt
  59. 4 5
      app/src/main/java/io/legado/app/ui/book/read/sheet/ReadAloudConfigContent.kt
  60. 5 6
      app/src/main/java/io/legado/app/ui/book/read/sheet/ReadAloudScreen.kt
  61. 5 16
      app/src/main/java/io/legado/app/ui/book/read/sheet/ReadStyleSheet.kt
  62. 8 14
      app/src/main/java/io/legado/app/ui/book/read/sheet/ReaderBookSheet.kt
  63. 3 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/ShadowSetSheet.kt
  64. 2 3
      app/src/main/java/io/legado/app/ui/book/read/sheet/SimulatedReadingSheet.kt
  65. 26 103
      app/src/main/java/io/legado/app/ui/book/read/sheet/SystemMenuPage.kt
  66. 7 11
      app/src/main/java/io/legado/app/ui/book/read/sheet/TextSelectMenuConfigSheet.kt
  67. 26 52
      app/src/main/java/io/legado/app/ui/book/read/sheet/TextTitleSheet.kt
  68. 9 4
      app/src/main/java/io/legado/app/ui/book/read/sheet/UnderlineConfigSheet.kt
  69. 16 46
      app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordOverviewScreen.kt
  70. 20 39
      app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt
  71. 2 9
      app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordCharts.kt
  72. 1 2
      app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordHeatmap.kt
  73. 3 10
      app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordListItems.kt
  74. 2 5
      app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordStats.kt
  75. 3 10
      app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordSummary.kt
  76. 2 3
      app/src/main/java/io/legado/app/ui/book/readaloud/casting/BookVoiceCastingScreen.kt
  77. 1 2
      app/src/main/java/io/legado/app/ui/book/readaloud/cloudtts/CloudTtsScreen.kt
  78. 7 20
      app/src/main/java/io/legado/app/ui/book/readaloud/player/ReadAloudPlayerScreen.kt
  79. 2 3
      app/src/main/java/io/legado/app/ui/book/search/ScopeSelectSheet.kt
  80. 10 29
      app/src/main/java/io/legado/app/ui/book/search/SearchScreen.kt
  81. 1 4
      app/src/main/java/io/legado/app/ui/book/search/SearchSourceSection.kt
  82. 6 12
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt
  83. 1 4
      app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt
  84. 10 8
      app/src/main/java/io/legado/app/ui/book/toc/rule/preview/TxtTocRulePreviewScreen.kt
  85. 3 7
      app/src/main/java/io/legado/app/ui/config/ai/AiProviderEditScreen.kt
  86. 3 5
      app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt
  87. 3 5
      app/src/main/java/io/legado/app/ui/config/coverConfig/CoverAlbumManageScreen.kt
  88. 3 6
      app/src/main/java/io/legado/app/ui/config/coverConfig/CoverAlbumSelectSheet.kt
  89. 2 3
      app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt
  90. 3 3
      app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt
  91. 2 3
      app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt
  92. 13 16
      app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt
  93. 3 3
      app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt
  94. 4 4
      app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt
  95. 3 4
      app/src/main/java/io/legado/app/ui/config/themeConfig/MainNavigationSettingsSheet.kt
  96. 3 6
      app/src/main/java/io/legado/app/ui/config/themeConfig/NavIconManageSheet.kt
  97. 10 0
      app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigContract.kt
  98. 11 3
      app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigRouteScreen.kt
  99. 110 15
      app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt
  100. 119 17
      app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigViewModel.kt

+ 23 - 0
app/src/main/java/io/legado/app/data/repository/ThemePackageSettingsRepository.kt

@@ -100,6 +100,20 @@ class ThemePackageSettingsRepository : ThemePackageSettingsGateway {
         bgImageDark = AppConfigStore.getString(PreferKey.bgImageN),
         bgImageBlurring = int(PreferKey.bgImageBlurring, 0),
         bgImageNBlurring = int(PreferKey.bgImageNBlurring, 0),
+        largeContainerBackgroundImageLight = AppConfigStore.getString(
+            PreferKey.largeContainerBackgroundImageLight
+        ),
+        largeContainerBackgroundImageDark = AppConfigStore.getString(
+            PreferKey.largeContainerBackgroundImageDark
+        ),
+        itemBackgroundImageLight = AppConfigStore.getString(PreferKey.itemBackgroundImageLight),
+        itemBackgroundImageDark = AppConfigStore.getString(PreferKey.itemBackgroundImageDark),
+        enableContainerBackgroundImage = boolean(
+            PreferKey.enableContainerBackgroundImage,
+            false,
+        ),
+        appColumnBackgroundOpacity = int(PreferKey.appColumnBackgroundOpacity, 100),
+        glassCardBackgroundOpacity = int(PreferKey.glassCardBackgroundOpacity, 100),
         appFontPath = AppConfigStore.getString(PreferKey.appFontPath),
         coverLoadOnlyWifi = boolean(PreferKey.loadCoverOnlyWifi, false),
         coverUseDefault = boolean(PreferKey.useDefaultCover, false),
@@ -215,6 +229,15 @@ internal fun ThemeExportData.toPreferenceValues(): Map<String, Any?> {
                 PreferKey.bgImageN to data.bgImageDark,
                 PreferKey.bgImageBlurring to data.bgImageBlurring,
                 PreferKey.bgImageNBlurring to data.bgImageNBlurring,
+                PreferKey.largeContainerBackgroundImageLight to
+                    data.largeContainerBackgroundImageLight,
+                PreferKey.largeContainerBackgroundImageDark to
+                    data.largeContainerBackgroundImageDark,
+                PreferKey.itemBackgroundImageLight to data.itemBackgroundImageLight,
+                PreferKey.itemBackgroundImageDark to data.itemBackgroundImageDark,
+                PreferKey.enableContainerBackgroundImage to data.enableContainerBackgroundImage,
+                PreferKey.appColumnBackgroundOpacity to data.appColumnBackgroundOpacity,
+                PreferKey.glassCardBackgroundOpacity to data.glassCardBackgroundOpacity,
                 PreferKey.appFontPath to data.appFontPath,
                 PreferKey.loadCoverOnlyWifi to data.coverLoadOnlyWifi,
                 PreferKey.useDefaultCover to data.coverUseDefault,

+ 7 - 0
app/src/main/java/io/legado/app/domain/model/settings/ThemeExportData.kt

@@ -83,6 +83,13 @@ data class ThemeExportData(
     val bgImageDark: String? = null,
     val bgImageBlurring: Int = 0,
     val bgImageNBlurring: Int = 0,
+    val largeContainerBackgroundImageLight: String? = null,
+    val largeContainerBackgroundImageDark: String? = null,
+    val itemBackgroundImageLight: String? = null,
+    val itemBackgroundImageDark: String? = null,
+    val enableContainerBackgroundImage: Boolean = false,
+    val appColumnBackgroundOpacity: Int = 100,
+    val glassCardBackgroundOpacity: Int = 100,
     val appFontPath: String? = null,
     val selectedCoverAlbumId: String? = null,
     val coverLoadOnlyWifi: Boolean = false,

+ 7 - 0
app/src/main/java/io/legado/app/domain/model/settings/ThemeSettings.kt

@@ -50,6 +50,13 @@ data class ThemeSettings(
     val backgroundImageDark: String? = null,
     val backgroundImageBlurring: Int = 0,
     val backgroundImageDarkBlurring: Int = 0,
+    val largeContainerBackgroundImageLight: String? = null,
+    val largeContainerBackgroundImageDark: String? = null,
+    val itemBackgroundImageLight: String? = null,
+    val itemBackgroundImageDark: String? = null,
+    val enableContainerBackgroundImage: Boolean = false,
+    val appColumnBackgroundOpacity: Int = 100,
+    val glassCardBackgroundOpacity: Int = 100,
     val enableItemDivider: Boolean = false,
     val itemDividerWidth: Float = 1f,
     val itemDividerLength: Float = 80f,

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

@@ -30,6 +30,10 @@ object ThemeImportExport {
         val assetPaths = mapOf(
             "bgImageLight" to data.bgImageLight,
             "bgImageDark" to data.bgImageDark,
+            "largeContainerBackgroundImageLight" to data.largeContainerBackgroundImageLight,
+            "largeContainerBackgroundImageDark" to data.largeContainerBackgroundImageDark,
+            "itemBackgroundImageLight" to data.itemBackgroundImageLight,
+            "itemBackgroundImageDark" to data.itemBackgroundImageDark,
             "navIconHome" to data.navIconHome,
             "navIconBookshelf" to data.navIconBookshelf,
             "navIconExplore" to data.navIconExplore,
@@ -109,6 +113,16 @@ object ThemeImportExport {
             data = data.copy(
                 bgImageLight = embeddedAssets.paths["bgImageLight"] ?: data.bgImageLight,
                 bgImageDark = embeddedAssets.paths["bgImageDark"] ?: data.bgImageDark,
+                largeContainerBackgroundImageLight =
+                    embeddedAssets.paths["largeContainerBackgroundImageLight"]
+                        ?: data.largeContainerBackgroundImageLight,
+                largeContainerBackgroundImageDark =
+                    embeddedAssets.paths["largeContainerBackgroundImageDark"]
+                        ?: data.largeContainerBackgroundImageDark,
+                itemBackgroundImageLight = embeddedAssets.paths["itemBackgroundImageLight"]
+                    ?: data.itemBackgroundImageLight,
+                itemBackgroundImageDark = embeddedAssets.paths["itemBackgroundImageDark"]
+                    ?: data.itemBackgroundImageDark,
                 navIconHome = embeddedAssets.paths["navIconHome"] ?: data.navIconHome,
                 navIconBookshelf = embeddedAssets.paths["navIconBookshelf"]
                     ?: data.navIconBookshelf,
@@ -145,6 +159,13 @@ object ThemeImportExport {
                         File(folder, "theme_asset_${UUID.randomUUID()}.jpg")
                     }
 
+                    key.contains("ContainerBackgroundImage") -> {
+                        val baseDir = appCtx.getExternalFilesDir(null) ?: appCtx.filesDir
+                        val folder = File(baseDir, "container_background/$key")
+                        folder.mkdirs()
+                        File(folder, "theme_asset_${UUID.randomUUID()}.png")
+                    }
+
                     key.startsWith("navIcon") -> {
                         val folder = File(appCtx.filesDir, "nav_icons")
                         folder.mkdirs()

+ 77 - 9
app/src/main/java/io/legado/app/help/config/ThemePackageManager.kt

@@ -54,6 +54,10 @@ class ThemePackageManager(
 
         private const val ASSET_BACKGROUND_LIGHT = "background.light"
         private const val ASSET_BACKGROUND_DARK = "background.dark"
+        private const val ASSET_CONTAINER_LARGE_LIGHT = "container.large.light"
+        private const val ASSET_CONTAINER_LARGE_DARK = "container.large.dark"
+        private const val ASSET_CONTAINER_ITEM_LIGHT = "container.item.light"
+        private const val ASSET_CONTAINER_ITEM_DARK = "container.item.dark"
         private const val ASSET_NAV_HOME = "navigation.home"
         private const val ASSET_NAV_BOOKSHELF = "navigation.bookshelf"
         private const val ASSET_NAV_EXPLORE = "navigation.explore"
@@ -137,6 +141,12 @@ class ThemePackageManager(
                         manifest.config.copy(
                             bgImageLight = localAssets[ASSET_BACKGROUND_LIGHT],
                             bgImageDark = localAssets[ASSET_BACKGROUND_DARK],
+                            largeContainerBackgroundImageLight =
+                                localAssets[ASSET_CONTAINER_LARGE_LIGHT],
+                            largeContainerBackgroundImageDark =
+                                localAssets[ASSET_CONTAINER_LARGE_DARK],
+                            itemBackgroundImageLight = localAssets[ASSET_CONTAINER_ITEM_LIGHT],
+                            itemBackgroundImageDark = localAssets[ASSET_CONTAINER_ITEM_DARK],
                             navIconHome = localAssets[ASSET_NAV_HOME].orEmpty(),
                             navIconBookshelf = localAssets[ASSET_NAV_BOOKSHELF].orEmpty(),
                             navIconExplore = localAssets[ASSET_NAV_EXPLORE].orEmpty(),
@@ -299,6 +309,10 @@ class ThemePackageManager(
             val data = manifest.config.copy(
                 bgImageLight = localAssets[ASSET_BACKGROUND_LIGHT],
                 bgImageDark = localAssets[ASSET_BACKGROUND_DARK],
+                largeContainerBackgroundImageLight = localAssets[ASSET_CONTAINER_LARGE_LIGHT],
+                largeContainerBackgroundImageDark = localAssets[ASSET_CONTAINER_LARGE_DARK],
+                itemBackgroundImageLight = localAssets[ASSET_CONTAINER_ITEM_LIGHT],
+                itemBackgroundImageDark = localAssets[ASSET_CONTAINER_ITEM_DARK],
                 navIconHome = localAssets[ASSET_NAV_HOME].orEmpty(),
                 navIconBookshelf = localAssets[ASSET_NAV_BOOKSHELF].orEmpty(),
                 navIconExplore = localAssets[ASSET_NAV_EXPLORE].orEmpty(),
@@ -402,6 +416,12 @@ class ThemePackageManager(
                 data = manifest.config.copy(
                     bgImageLight = localAssets[ASSET_BACKGROUND_LIGHT],
                     bgImageDark = localAssets[ASSET_BACKGROUND_DARK],
+                    largeContainerBackgroundImageLight =
+                        localAssets[ASSET_CONTAINER_LARGE_LIGHT],
+                    largeContainerBackgroundImageDark =
+                        localAssets[ASSET_CONTAINER_LARGE_DARK],
+                    itemBackgroundImageLight = localAssets[ASSET_CONTAINER_ITEM_LIGHT],
+                    itemBackgroundImageDark = localAssets[ASSET_CONTAINER_ITEM_DARK],
                     navIconHome = localAssets[ASSET_NAV_HOME].orEmpty(),
                     navIconBookshelf = localAssets[ASSET_NAV_BOOKSHELF].orEmpty(),
                     navIconExplore = localAssets[ASSET_NAV_EXPLORE].orEmpty(),
@@ -495,6 +515,26 @@ class ThemePackageManager(
         val sources = mapOf(
             "bgImageLight" to AssetSource(ASSET_BACKGROUND_LIGHT, null, "assets/background/light"),
             "bgImageDark" to AssetSource(ASSET_BACKGROUND_DARK, null, "assets/background/dark"),
+            "largeContainerBackgroundImageLight" to AssetSource(
+                ASSET_CONTAINER_LARGE_LIGHT,
+                null,
+                "assets/container/large/light",
+            ),
+            "largeContainerBackgroundImageDark" to AssetSource(
+                ASSET_CONTAINER_LARGE_DARK,
+                null,
+                "assets/container/large/dark",
+            ),
+            "itemBackgroundImageLight" to AssetSource(
+                ASSET_CONTAINER_ITEM_LIGHT,
+                null,
+                "assets/container/item/light",
+            ),
+            "itemBackgroundImageDark" to AssetSource(
+                ASSET_CONTAINER_ITEM_DARK,
+                null,
+                "assets/container/item/dark",
+            ),
             "navIconHome" to AssetSource(ASSET_NAV_HOME, null, "assets/navigation/home"),
             "navIconBookshelf" to AssetSource(
                 ASSET_NAV_BOOKSHELF,
@@ -658,12 +698,11 @@ class ThemePackageManager(
         return entries.mapNotNull { (key, entryPath) ->
             val source = resolvePackageFile(root, entryPath)
             require(source.isFile) { "主题资源不存在: $entryPath" }
-            val extension = source.extension
-                .lowercase()
-                .takeIf { it.matches(Regex("[a-z0-9]{1,8}")) }
-                ?: "asset"
+            val extension = sourceExtension(source.absolutePath, key)
             val targetDir = when (key) {
-                ASSET_BACKGROUND_LIGHT, ASSET_BACKGROUND_DARK -> {
+                ASSET_BACKGROUND_LIGHT, ASSET_BACKGROUND_DARK,
+                ASSET_CONTAINER_LARGE_LIGHT, ASSET_CONTAINER_LARGE_DARK,
+                ASSET_CONTAINER_ITEM_LIGHT, ASSET_CONTAINER_ITEM_DARK -> {
                     File(context.getExternalFilesDir(null) ?: context.filesDir, "theme_assets")
                 }
 
@@ -890,6 +929,10 @@ class ThemePackageManager(
     private fun ThemeExportData.toPortableConfig() = copy(
         bgImageLight = null,
         bgImageDark = null,
+        largeContainerBackgroundImageLight = null,
+        largeContainerBackgroundImageDark = null,
+        itemBackgroundImageLight = null,
+        itemBackgroundImageDark = null,
         navIconHome = "",
         navIconBookshelf = "",
         navIconExplore = "",
@@ -909,6 +952,26 @@ class ThemePackageManager(
     private fun assetSources(config: ThemeExportData) = listOf(
         AssetSource(ASSET_BACKGROUND_LIGHT, config.bgImageLight, "assets/background/light"),
         AssetSource(ASSET_BACKGROUND_DARK, config.bgImageDark, "assets/background/dark"),
+        AssetSource(
+            ASSET_CONTAINER_LARGE_LIGHT,
+            config.largeContainerBackgroundImageLight,
+            "assets/container/large/light",
+        ),
+        AssetSource(
+            ASSET_CONTAINER_LARGE_DARK,
+            config.largeContainerBackgroundImageDark,
+            "assets/container/large/dark",
+        ),
+        AssetSource(
+            ASSET_CONTAINER_ITEM_LIGHT,
+            config.itemBackgroundImageLight,
+            "assets/container/item/light",
+        ),
+        AssetSource(
+            ASSET_CONTAINER_ITEM_DARK,
+            config.itemBackgroundImageDark,
+            "assets/container/item/dark",
+        ),
         AssetSource(ASSET_NAV_HOME, config.navIconHome, "assets/navigation/home"),
         AssetSource(
             ASSET_NAV_BOOKSHELF,
@@ -931,10 +994,11 @@ class ThemePackageManager(
     }
 
     private fun sourceExtension(path: String, key: String): String {
-        val candidate = Uri.parse(path).lastPathSegment
-            ?.substringAfterLast('.', "")
-            ?.lowercase()
-            ?.takeIf { it.matches(Regex("[a-z0-9]{1,8}")) }
+        val fileName = Uri.parse(path).lastPathSegment.orEmpty()
+        if (fileName.endsWith(".9.png", ignoreCase = true)) return "9.png"
+        val candidate = fileName.substringAfterLast('.', "")
+            .lowercase()
+            .takeIf { it.matches(Regex("[a-z0-9]{1,8}")) }
         return candidate ?: if (key == ASSET_FONT) "ttf" else "img"
     }
 
@@ -1006,6 +1070,10 @@ class ThemePackageManager(
             get() = when (key) {
                 ASSET_BACKGROUND_LIGHT -> "bgImageLight"
                 ASSET_BACKGROUND_DARK -> "bgImageDark"
+                ASSET_CONTAINER_LARGE_LIGHT -> "largeContainerBackgroundImageLight"
+                ASSET_CONTAINER_LARGE_DARK -> "largeContainerBackgroundImageDark"
+                ASSET_CONTAINER_ITEM_LIGHT -> "itemBackgroundImageLight"
+                ASSET_CONTAINER_ITEM_DARK -> "itemBackgroundImageDark"
                 ASSET_NAV_HOME -> "navIconHome"
                 ASSET_NAV_BOOKSHELF -> "navIconBookshelf"
                 ASSET_NAV_EXPLORE -> "navIconExplore"

+ 2 - 10
app/src/main/java/io/legado/app/ui/about/AboutScreen.kt

@@ -35,7 +35,6 @@ import io.legado.app.R
 import io.legado.app.constant.AppConst.appInfo
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.ThemeResolver
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.SettingItemWithDivider
 import io.legado.app.ui.widget.components.SplicedColumnGroup
@@ -105,7 +104,7 @@ private fun MaterialAboutScreen(
             )
         }
     ) { padding ->
-        AppColumn(
+        Column(
             modifier = Modifier
                 .padding(padding)
                 .verticalScroll(rememberScrollState())
@@ -201,14 +200,7 @@ private fun MaterialAboutScreen(
                 SettingItemWithDivider {
                     SettingItem(
                         title = stringResource(R.string.disclaimer),
-                        onClick = {
-                            onIntent(
-                                AboutIntent.ShowMdFile(
-                                    disclaimerTitle,
-                                    "disclaimer.md"
-                                )
-                            )
-                        }
+                        onClick = { onIntent(AboutIntent.ShowMdFile(disclaimerTitle, "disclaimer.md")) }
                     )
                 }
                 SettingItemWithDivider {

+ 3 - 4
app/src/main/java/io/legado/app/ui/about/AboutSheets.kt

@@ -24,7 +24,6 @@ import io.legado.app.R
 import io.legado.app.constant.AppConst.appInfo
 import io.legado.app.help.update.AppUpdate
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.button.PrimaryButton
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.text.AppText
@@ -44,7 +43,7 @@ fun MarkdownSheet(
         title = title,
     ) {
         SelectionContainer {
-            AppColumn(
+            Column(
                 modifier = Modifier
                     .fillMaxWidth()
                     .verticalScroll(rememberScrollState())
@@ -79,8 +78,8 @@ fun UpdateSheet(
         onDismissRequest = onDismissRequest,
         title = title,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .verticalScroll(rememberScrollState())
         ) {

+ 3 - 3
app/src/main/java/io/legado/app/ui/about/CrashReportScreen.kt

@@ -24,7 +24,6 @@ import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
 import io.legado.app.ui.widget.components.icon.AppIcons
@@ -61,13 +60,14 @@ fun CrashReportScreen(
             )
         }
     ) { padding ->
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxSize()
                 .padding(padding)
                 .padding(horizontal = 16.dp, vertical = 12.dp),
             verticalArrangement = Arrangement.spacedBy(16.dp)
         ) {
+
             Icon(
                 imageVector = AppIcons.BugReport,
                 contentDescription = null,

+ 6 - 14
app/src/main/java/io/legado/app/ui/about/MiuixAboutScreen.kt

@@ -55,7 +55,6 @@ import io.legado.app.ui.util.pageContentPadding
 import io.legado.app.ui.util.pageScrollModifiers
 import io.legado.app.ui.util.rememberBlurBackdrop
 import io.legado.app.ui.util.shouldShowSplitPane
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.effect.BgEffectBackground
 import io.legado.app.ui.widget.components.effect.ColorBlendToken
 import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
@@ -249,8 +248,8 @@ private fun AboutContent(
         bgModifier = if (backdrop != null) Modifier.layerBackdrop(backdrop) else Modifier,
         alpha = { 1f - scrollProgress },
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(
                     top = logoPadding.calculateTopPadding() + 52.dp,
@@ -356,10 +355,10 @@ private fun AboutContent(
             }
 
             item(key = "about") {
-                AppColumn(
-                    Modifier
+                Column(
+                    modifier = Modifier
                         .fillParentMaxHeight()
-                        .padding(bottom = scrollPadding.calculateBottomPadding())
+                        .padding(bottom = scrollPadding.calculateBottomPadding()),
                 ) {
                     Card(
                         modifier = Modifier
@@ -440,14 +439,7 @@ private fun AboutContent(
                         )
                         ArrowPreference(
                             title = stringResource(R.string.license),
-                            onClick = {
-                                onIntent(
-                                    AboutIntent.ShowMdFile(
-                                        licenseTitle,
-                                        "LICENSE.md"
-                                    )
-                                )
-                            },
+                            onClick = { onIntent(AboutIntent.ShowMdFile(licenseTitle, "LICENSE.md")) },
                         )
                         ArrowPreference(
                             title = stringResource(R.string.disclaimer),

+ 10 - 15
app/src/main/java/io/legado/app/ui/ai/chat/AiChatScreen.kt

@@ -91,7 +91,6 @@ import io.legado.app.domain.model.AiMessagePart
 import io.legado.app.domain.model.AiMessageRole
 import io.legado.app.domain.model.AiReasoningLevel
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
@@ -385,8 +384,8 @@ fun AiChatScreen(
                 }
 
                 // Draw behind both the floating input and the system navigation/IME area.
-                AppColumn(
-                    Modifier
+                Column(
+                    modifier = Modifier
                         .align(Alignment.BottomCenter)
                         .fillMaxWidth()
                 ) {
@@ -426,8 +425,8 @@ fun AiChatScreen(
                             .fillMaxWidth()
                             .onSizeChanged { bottomOverlayHeightPx = it.height }
                     ) {
-                        AppColumn(
-                            Modifier
+                        Column(
+                            modifier = Modifier
                                 .fillMaxWidth()
                                 .padding(top = 32.dp)
                         ) {
@@ -535,8 +534,8 @@ fun AiChatScreen(
                                 shape = RoundedCornerShape(50),
                                 color = LegadoTheme.colorScheme.surfaceContainerLow
                             ) {
-                                AppColumn(
-                                    Modifier
+                                Column(
+                                    modifier = Modifier
                                         .height(40.dp)
                                         .padding(horizontal = 12.dp),
                                     horizontalAlignment = Alignment.Start,
@@ -598,9 +597,7 @@ private fun PendingToolConfirmationCard(
             .fillMaxWidth()
             .padding(top = 8.dp)
     ) {
-        AppColumn(
-            Modifier.padding(12.dp)
-        ) {
+        Column(modifier = Modifier.padding(12.dp)) {
             AppText(
                 text = stringResource(R.string.ai_tool_confirmation),
                 style = LegadoTheme.typography.labelMedium,
@@ -730,8 +727,8 @@ private fun RecentChatsDrawer(
                         LegadoTheme.colorScheme.surface
                     }
                 ) {
-                    AppColumn(
-                        Modifier
+                    Column(
+                        modifier = Modifier
                             .fillMaxWidth()
                             .padding(horizontal = 12.dp, vertical = 10.dp)
                     ) {
@@ -909,9 +906,7 @@ private fun ChatInputBar(
                     .padding(horizontal = 16.dp, vertical = 14.dp),
                 verticalAlignment = Alignment.CenterVertically
             ) {
-                AppColumn(
-                    Modifier.weight(1f)
-                ) {
+                Column(modifier = Modifier.weight(1f)) {
                     AppText(
                         text = label,
                         style = LegadoTheme.typography.bodyLarge,

+ 5 - 10
app/src/main/java/io/legado/app/ui/ai/chat/AiGeneratedMessageContent.kt

@@ -43,7 +43,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.domain.model.AiMessagePart
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.button.series.SmallPlainButton
 import io.legado.app.ui.widget.components.image.cover.CoilBookCover
 import io.legado.app.ui.widget.components.text.AppText
@@ -75,8 +74,8 @@ fun AiGeneratedMessageContent(
         .flatMap { block -> block.steps.filterIsInstance<AiThinkingStep.ToolStep>() }
     val contentBlocks = groupedParts.filterIsInstance<AiMessagePartBlock.ContentBlock>()
 
-    AppColumn(
-        modifier.animateContentSize()
+    Column(
+        modifier = modifier.animateContentSize()
     ) {
         if (showHeader) {
             AppText(
@@ -265,7 +264,7 @@ private fun BookResultsList(
 ) {
     if (books.isEmpty()) return
     Spacer(modifier = Modifier.height(10.dp))
-    AppColumn(
+    Column(
         modifier = Modifier.fillMaxWidth(),
         verticalArrangement = Arrangement.spacedBy(6.dp)
     ) {
@@ -307,9 +306,7 @@ private fun ChatBookResultItem(
                 .height(68.dp)
         )
         Spacer(modifier = Modifier.width(10.dp))
-        AppColumn(
-            Modifier.weight(1f)
-        ) {
+        Column(modifier = Modifier.weight(1f)) {
             AppText(
                 text = book.name.ifBlank { book.bookUrl },
                 style = LegadoTheme.typography.titleSmall,
@@ -375,9 +372,7 @@ private fun TracePanel(
 ) {
     var expanded by rememberSaveable(title) { mutableStateOf(false) }
 
-    AppColumn(
-        Modifier.fillMaxWidth()
-    ) {
+    Column(modifier = Modifier.fillMaxWidth()) {
         Row(
             modifier = Modifier
                 .fillMaxWidth()

+ 5 - 3
app/src/main/java/io/legado/app/ui/ai/chat/AiReasoningCard.kt

@@ -45,7 +45,6 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.isActive
@@ -130,11 +129,12 @@ fun ReasoningCard(
     val (state, loading) = rememberReasoningState(text, isStreaming, messageCreatedAt)
     val fadeHeight = 64f
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
             .animateContentSize()
     ) {
+        // Header row
         Row(
             modifier = Modifier
                 .fillMaxWidth()
@@ -193,6 +193,8 @@ fun ReasoningCard(
                 tint = LegadoTheme.colorScheme.outline
             )
         }
+
+        // Content area
         if (state.expandState != ReasoningCardState.Collapsed) {
             val isPreview = state.expandState == ReasoningCardState.Preview
             val contentModifier = Modifier

+ 3 - 5
app/src/main/java/io/legado/app/ui/ai/chat/AiThinkingCard.kt

@@ -30,7 +30,6 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import io.legado.app.domain.model.AiMessagePart
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.icon.AppIcon
@@ -134,7 +133,7 @@ fun AiThinkingCard(
             enter = expandVertically(),
             exit = shrinkVertically()
         ) {
-            io.legado.app.ui.widget.components.AppColumn(
+            Column(
                 modifier = Modifier
                     .fillMaxWidth()
                     .heightIn(max = 400.dp)
@@ -153,7 +152,6 @@ fun AiThinkingCard(
                                     .padding(horizontal = 12.dp, vertical = 10.dp)
                             )
                         }
-
                         is AiThinkingStep.ToolStep -> {
                             ToolStepContent(tool = step.tool)
                         }
@@ -168,8 +166,8 @@ fun AiThinkingCard(
 private fun ToolStepContent(tool: AiMessagePart.Tool) {
     val hasContent = tool.output.isNotBlank() || tool.input.isNotBlank()
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .padding(start = 12.dp, end = 12.dp, top = 10.dp, bottom = 10.dp)
     ) {

+ 10 - 12
app/src/main/java/io/legado/app/ui/ai/chat/AiThinkingStepsCard.kt

@@ -37,9 +37,7 @@ import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.domain.model.AiMessagePart
-import io.legado.app.domain.model.AiToolApprovalState
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.text.AppText
 
@@ -70,11 +68,12 @@ fun AiThinkingStepsCard(
     NormalCard(
         modifier = modifier.fillMaxWidth(),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .animateContentSize()
                 .padding(horizontal = 12.dp, vertical = 8.dp)
         ) {
+            // Collapse/expand toggle - no padding, ripple clipped by card
             if (canCollapse) {
                 Row(
                     modifier = Modifier
@@ -96,16 +95,15 @@ fun AiThinkingStepsCard(
                         text = if (expanded) {
                             stringResource(R.string.ai_thinking_collapse)
                         } else {
-                            stringResource(
-                                R.string.ai_thinking_show_more,
-                                steps.size - collapsedVisibleCount
-                            )
+                            stringResource(R.string.ai_thinking_show_more, steps.size - collapsedVisibleCount)
                         },
                         style = LegadoTheme.typography.labelMedium,
                         color = LegadoTheme.colorScheme.primary,
                     )
                 }
             }
+
+            // Content
             Column {
                 visibleSteps.forEachIndexed { index, step ->
                     ThinkingStepRow(
@@ -159,8 +157,7 @@ private fun ToolStepRow(
     var expanded by remember { mutableStateOf(false) }
     val hasContent = tool.input.isNotBlank() || tool.output.isNotBlank()
 
-    AppColumn(
-    ) {
+    Column {
         Row(
             modifier = Modifier
                 .fillMaxWidth()
@@ -203,9 +200,8 @@ private fun ToolStepRow(
             // Status
             val statusText = when {
                 tool.output.isNotBlank() -> stringResource(R.string.ai_tool_done)
-                tool.approvalState == AiToolApprovalState.PENDING ->
+                tool.approvalState == io.legado.app.domain.model.AiToolApprovalState.PENDING ->
                     stringResource(R.string.ai_tool_pending)
-
                 else -> stringResource(R.string.ai_tool_running)
             }
             AppText(
@@ -223,6 +219,8 @@ private fun ToolStepRow(
                 )
             }
         }
+
+        // Expandable tool details
         AnimatedVisibility(
             visible = expanded,
             enter = fadeIn() + expandVertically(),

+ 4 - 10
app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt

@@ -76,7 +76,6 @@ 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 androidx.lifecycle.compose.collectAsStateWithLifecycle
-import io.legado.app.ui.widget.components.AppColumn
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
@@ -168,8 +167,7 @@ fun AllBookmarkScreen(
     AppScaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
-            AppColumn(
-            ) {
+            Column {
                 GlassMediumFlexibleTopAppBar(
                     title = stringResource(R.string.all_bookmark),
                     scrollBehavior = scrollBehavior,
@@ -244,8 +242,8 @@ fun AllBookmarkScreen(
             }
         }
     ) { paddingValues ->
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxSize()
         ) {
             AnimatedContent(
@@ -309,11 +307,7 @@ fun AllBookmarkScreen(
                                             subtitle = headerKey.bookAuthor,
                                             isCollapsed = isCollapsed,
                                             onToggle = {
-                                                onIntent(
-                                                    AllBookmarkIntent.ToggleGroupCollapse(
-                                                        headerKey
-                                                    )
-                                                )
+                                                onIntent(AllBookmarkIntent.ToggleGroupCollapse(headerKey))
                                             },
                                             isMiuix = isMiuix
                                         )

+ 5 - 8
app/src/main/java/io/legado/app/ui/book/cache/manage/BookCacheManageScreen.kt

@@ -46,7 +46,6 @@ import io.legado.app.R
 import io.legado.app.data.entities.BookGroup
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
@@ -221,7 +220,7 @@ private fun BookCacheManageScreen(
         }
     ) { paddingValues ->
         if (state.isLoading) {
-            AppColumn(
+            Column(
                 modifier = Modifier
                     .fillMaxSize()
                     .padding(paddingValues),
@@ -420,8 +419,8 @@ private fun BookCacheBookCard(
         onClick = onToggleExpanded,
         containerColor = LegadoTheme.colorScheme.surfaceContainer
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(8.dp)
@@ -493,12 +492,10 @@ private fun BookCacheBookCard(
                                 R.string.pause_book_download,
                                 item.name
                             )
-
                             item.isPaused -> stringResource(
                                 R.string.resume_book_download,
                                 item.name
                             )
-
                             else -> stringResource(R.string.start_book_download, item.name)
                         }
                     )
@@ -543,8 +540,8 @@ private fun BookCacheChapterRow(
         horizontalArrangement = Arrangement.spacedBy(8.dp),
         verticalAlignment = Alignment.CenterVertically
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .weight(1f)
                 .semantics(mergeDescendants = true) {
                     contentDescription = chapterDescription

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceMigrationOptionsSheet.kt

@@ -17,7 +17,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.domain.usecase.ChangeSourceMigrationOptions
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
 import io.legado.app.ui.widget.components.checkBox.CheckboxItem
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
@@ -59,7 +58,7 @@ fun ChangeSourceMigrationOptionsSheet(
         onDismissRequest = onDismissRequest,
         title = title,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.fillMaxWidth(),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt

@@ -32,7 +32,6 @@ import io.legado.app.R
 import io.legado.app.data.entities.BookGroup
 import io.legado.app.data.entities.TagGroupRule
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
@@ -140,8 +139,8 @@ fun GroupEditContent(
         }
     }
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .padding(bottom = 16.dp)
             .verticalScroll(rememberScrollState()),

+ 2 - 9
app/src/main/java/io/legado/app/ui/book/import/local/ImportBookScreen.kt

@@ -56,7 +56,6 @@ import io.legado.app.lib.dialogs.alert
 import io.legado.app.lib.dialogs.selector
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.ActionItem
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppPullToRefresh
 import io.legado.app.ui.widget.components.EmptyMessage
 import io.legado.app.ui.widget.components.SelectionActions
@@ -531,9 +530,7 @@ private fun ImportBookItem(
 
             Spacer(modifier = Modifier.width(16.dp))
 
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
                 AppText(
                     text = item.name,
                     style = LegadoTheme.typography.bodyMedium,
@@ -554,11 +551,7 @@ private fun ImportBookItem(
                         )
                         Spacer(modifier = Modifier.width(6.dp))
                         AppText(
-                            text = "${ConvertUtils.formatFileSize(item.size)} - ${
-                                AppConst.dateFormat.format(
-                                    item.lastModified
-                                )
-                            }",
+                            text = "${ConvertUtils.formatFileSize(item.size)} - ${AppConst.dateFormat.format(item.lastModified)}",
                             style = LegadoTheme.typography.labelMedium,
                             color = LegadoTheme.colorScheme.onSurfaceVariant
                         )

+ 6 - 6
app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt

@@ -69,7 +69,6 @@ import io.legado.app.lib.dialogs.selector
 import io.legado.app.model.remote.RemoteBook
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.ActionItem
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppPullToRefresh
 import io.legado.app.ui.widget.components.AppRadioButton
 import io.legado.app.ui.widget.components.AppTextField
@@ -396,8 +395,8 @@ private fun ServersSheetContent(
     onDelete: (Server) -> Unit,
     onDefault: () -> Unit
 ) {
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .navigationBarsPadding()
             .padding(bottom = 8.dp)
@@ -494,8 +493,8 @@ private fun ServerConfigSheetContent(
     var password by remember { mutableStateOf(configJson.optString("password")) }
     var passwordVisible by remember { mutableStateOf(false) }
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .navigationBarsPadding()
             .verticalScroll(rememberScrollState())
@@ -685,9 +684,10 @@ private fun RemoteBookItem(
 
             Spacer(modifier = Modifier.width(16.dp))
 
-            AppColumn(
+            Column(
                 modifier = Modifier.weight(1f)
             ) {
+
                 AppText(
                     text = book.filename.substringBeforeLast("."),
                     style = LegadoTheme.typography.bodyMedium,

+ 2 - 6
app/src/main/java/io/legado/app/ui/book/info/BookInfoReadRecordSheet.kt

@@ -28,7 +28,6 @@ import io.legado.app.R
 import io.legado.app.data.entities.readRecord.ReadRecordSession
 import io.legado.app.data.entities.readRecord.ReadRecordTimelineDay
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.EmptyMessage
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.card.TextCard
@@ -65,8 +64,7 @@ fun BookReadRecordSheet(
                     contentDescription = null,
                     tint = LegadoTheme.colorScheme.primary
                 )
-                AppColumn(
-                ) {
+                Column {
                     AppText(
                         text = stringResource(R.string.all_read_time),
                         style = LegadoTheme.typography.labelMedium,
@@ -142,9 +140,7 @@ private fun TimelineSessionRow(session: ReadRecordSession) {
         verticalAlignment = Alignment.CenterVertically
     ) {
         Spacer(modifier = Modifier.width(8.dp))
-        AppColumn(
-            Modifier.weight(1f)
-        ) {
+        Column(modifier = Modifier.weight(1f)) {
             AppText(
                 text = DateUtil.format(Date(session.endTime), "HH:mm"),
                 style = LegadoTheme.typography.bodyMedium,

+ 23 - 36
app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt

@@ -83,7 +83,6 @@ import io.legado.app.R
 import io.legado.app.constant.BookType
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.data.entities.BookGroup
-import io.legado.app.ui.main.homepage.HomepageBookItemUi
 import io.legado.app.ui.main.homepage.modules.BannerModule
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.LocalHazeState
@@ -96,7 +95,6 @@ import io.legado.app.ui.theme.fadingEdge
 import io.legado.app.ui.theme.rememberImageSeedColor
 import io.legado.app.ui.theme.rememberThemeOverride
 import io.legado.app.ui.theme.responsiveHazeEffectFixedStyle
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppPullToRefresh
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
@@ -305,8 +303,8 @@ private fun BookInfoScreenContent(
                             )
                         }
                         item {
-                            AppColumn(
-                                Modifier
+                            Column(
+                                modifier = Modifier
                                     .fillMaxWidth()
                                     .background(
                                         color = LegadoTheme.colorScheme.surface
@@ -353,12 +351,7 @@ private fun BookInfoScreenContent(
                                             onIntent(BookInfoIntent.RelatedBookClick(book))
                                         },
                                         onMoreClick = {
-                                            onIntent(
-                                                BookInfoIntent.RelatedBooksMore(
-                                                    module.title,
-                                                    module.resolvedUrl
-                                                )
-                                            )
+                                            onIntent(BookInfoIntent.RelatedBooksMore(module.title, module.resolvedUrl))
                                         },
                                     )
                                 }
@@ -894,8 +887,8 @@ private fun BookInfoHeader(
     sharedCoverKey: String?,
 ) {
     val coverDescription = stringResource(R.string.a11y_book_cover_actions, book.name)
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .background(
                 Brush.verticalGradient(
@@ -1141,8 +1134,8 @@ private fun BookInfoActionCard(
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
         contentColor = LegadoTheme.colorScheme.onSurface,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(horizontal = 8.dp, vertical = 12.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
@@ -1164,18 +1157,15 @@ private fun BookInfoSummary(
     tocLoadFailed: Boolean,
     onRemarkClick: () -> Unit,
 ) {
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .background(LegadoTheme.colorScheme.surface)
             .padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 120.dp),
         verticalArrangement = Arrangement.spacedBy(4.dp)
     ) {
         AnimatedTextLine(
-            text = stringResource(
-                R.string.toc_s,
-                book.durChapterTitle ?: stringResource(R.string.loading)
-            ),
+            text = stringResource(R.string.toc_s, book.durChapterTitle ?: stringResource(R.string.loading)),
             style = LegadoTheme.typography.titleMedium,
             fontWeight = FontWeight.Bold,
         )
@@ -1227,10 +1217,7 @@ private fun BookInfoSummary(
                 onClick = onRemarkClick,
                 containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
             ) {
-                Column(
-                    modifier = Modifier.padding(16.dp),
-                    verticalArrangement = Arrangement.spacedBy(4.dp)
-                ) {
+                Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(4.dp)) {
                     AnimatedTextLine(
                         text = remark,
                         style = LegadoTheme.typography.labelMediumEmphasized
@@ -1365,8 +1352,8 @@ private fun RelatedBooksBanner(
     onBookClick: (SearchBook, String?) -> Unit,
     onMoreClick: () -> Unit,
 ) {
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .padding(bottom = 16.dp)
     ) {
@@ -1391,7 +1378,7 @@ private fun RelatedBooksBanner(
             }
         }
         BannerModule(
-            books = books.map { HomepageBookItemUi(book = it) }
+            books = books.map { io.legado.app.ui.main.homepage.HomepageBookItemUi(book = it) }
                 .toImmutableList(),
             onClick = onBookClick,
             modifier = Modifier
@@ -1410,8 +1397,8 @@ private fun BookInfoCharacters(
     onKnowledgeClick: () -> Unit,
     onEventsClick: () -> Unit,
 ) {
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .background(LegadoTheme.colorScheme.surface)
             .padding(vertical = 8.dp),
@@ -1490,7 +1477,7 @@ private fun CharacterEntryCard(
         onClick = onClick,
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(10.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {
@@ -1561,8 +1548,8 @@ private fun BookInfoKnowledge(
     onViewAllClick: () -> Unit,
 ) {
     if (entries.isEmpty()) return
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .background(LegadoTheme.colorScheme.surface)
             .padding(vertical = 8.dp),
@@ -1613,7 +1600,7 @@ private fun KnowledgeInfoCard(
         modifier = Modifier.width(140.dp),
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {
@@ -1638,8 +1625,8 @@ private fun BookInfoEvents(
     onViewAllClick: () -> Unit,
 ) {
     if (events.isEmpty()) return
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .background(LegadoTheme.colorScheme.surface)
             .padding(vertical = 8.dp),
@@ -1693,7 +1680,7 @@ private fun EventInfoCard(
         modifier = Modifier.width(160.dp),
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {

+ 3 - 6
app/src/main/java/io/legado/app/ui/book/info/BookInfoSheets.kt

@@ -69,7 +69,6 @@ import io.legado.app.ui.book.search.ScopeSelectSheet
 import io.legado.app.ui.book.source.edit.BookSourceEditActivity
 import io.legado.app.ui.book.source.manage.BookSourceActivity
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.EmptyMessage
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
@@ -161,9 +160,7 @@ fun GroupSelectSheet(
             )
         }
     ) {
-        AppColumn(
-            Modifier.fillMaxWidth()
-        ) {
+        Column(modifier = Modifier.fillMaxWidth()) {
             LazyColumn(
                 modifier = Modifier.heightIn(max = 560.dp),
                 verticalArrangement = Arrangement.spacedBy(8.dp)
@@ -258,8 +255,8 @@ fun ChangeCoverSheet(
         }
         LazyVerticalGrid(columns = GridCells.Fixed(3), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
             items(items, key = { it.bookUrl + it.originName }) { item ->
-                AppColumn(
-                    Modifier
+                Column(
+                    modifier = Modifier
                         .fillMaxWidth()
                         .clip(RoundedCornerShape(4.dp))
                         .clickable {

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

@@ -58,7 +58,6 @@ import io.legado.app.R
 import io.legado.app.ui.book.changecover.ChangeCoverDialog
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.fadingEdge
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
@@ -153,8 +152,8 @@ fun BookInfoEditContent(
         }
     }
 
-    AppColumn(
-        modifier.padding(16.dp)
+    Column(
+        modifier = modifier.padding(16.dp)
     ) {
         Row(
             modifier = Modifier.fillMaxWidth(),
@@ -292,7 +291,7 @@ private fun BookKnowledgeEditCard(
     onOpenEventList: (String) -> Unit,
 ) {
     NormalCard(modifier = Modifier.fillMaxWidth()) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(16.dp),
             verticalArrangement = Arrangement.spacedBy(12.dp),
         ) {
@@ -413,12 +412,11 @@ fun KindEditor(
         mutable.add(to, mutable.removeAt(from))
         onKindListChange(mutable)
     }
-
     val reorderableState = rememberReorderableLazyListState(listState) { from, to ->
         moveKind(from.index, to.index)
     }
 
-    AppColumn(
+    Column(
         modifier = Modifier.padding(vertical = 8.dp),
         verticalArrangement = Arrangement.spacedBy(4.dp)
     ) {

+ 7 - 8
app/src/main/java/io/legado/app/ui/book/knowledge/BookCharacterDetailScreen.kt

@@ -40,7 +40,6 @@ import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.data.entities.BookCharacterProfile
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.EmptyMessage
@@ -160,7 +159,7 @@ private fun CharacterDetailContent(
     var dialogVoiceGender by remember(state.voiceGender) { mutableStateOf(state.voiceGender) }
     var dialogVoiceAgeBand by remember(state.voiceAgeBand) { mutableStateOf(state.voiceAgeBand) }
 
-    AppColumn(
+    Column(
         modifier = modifier.padding(horizontal = 16.dp, vertical = 12.dp),
         verticalArrangement = Arrangement.spacedBy(12.dp),
     ) {
@@ -245,7 +244,7 @@ private fun CharacterDetailContent(
         dismissText = stringResource(R.string.cancel),
         onDismiss = { showProfileDialog = false },
         content = {
-            AppColumn(verticalArrangement = Arrangement.spacedBy(12.dp)) {
+            Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                 AppTextField(
                     value = dialogName,
                     onValueChange = { dialogName = it },
@@ -339,7 +338,7 @@ private fun CharacterDeleteDialog(
         dismissText = stringResource(R.string.cancel),
         onDismiss = onDismiss,
         content = {
-            AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                 CheckboxItem(
                     stringResource(R.string.character_delete_relations),
                     checked = deleteRelations
@@ -474,8 +473,8 @@ private fun CharacterHeader(
             }
         }
 
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .weight(1f)
                 .clip(RoundedCornerShape(12.dp))
                 .clickable(onClick = onInfoClick)
@@ -527,7 +526,7 @@ private fun CharacterReadonlySection(
     isEmpty: Boolean,
     content: @Composable ColumnScope.() -> Unit,
 ) {
-    AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
         AppText(text = title, style = LegadoTheme.typography.titleMedium)
         if (isEmpty) {
             GlassCard {
@@ -555,7 +554,7 @@ private fun InfoCard(
         modifier = Modifier.fillMaxWidth(),
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {

+ 9 - 15
app/src/main/java/io/legado/app/ui/book/knowledge/BookCharacterListScreen.kt

@@ -1,10 +1,5 @@
 package io.legado.app.ui.book.knowledge
 
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
@@ -52,7 +47,6 @@ import io.legado.app.ui.ai.AiTaskResultSheet
 import io.legado.app.ui.ai.chat.ReasoningCard
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
@@ -208,7 +202,7 @@ private fun CharacterIdentifySheet(
     ) {
         when {
             sheet == null -> Unit
-            sheet.loading -> AppColumn(verticalArrangement = Arrangement.spacedBy(12.dp)) {
+            sheet.loading -> Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                 Box(
                     Modifier
                         .fillMaxWidth()
@@ -225,18 +219,18 @@ private fun CharacterIdentifySheet(
                 )
             }
 
-            sheet.error != null -> AppColumn(verticalArrangement = Arrangement.spacedBy(12.dp)) {
+            sheet.error != null -> Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                 AnimatedTextLine(sheet.error, color = LegadoTheme.colorScheme.error)
             }
 
-            sheet.candidates.isEmpty() -> AppColumn(verticalArrangement = Arrangement.spacedBy(12.dp)) {
+            sheet.candidates.isEmpty() -> Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                 AnimatedTextLine(
                     stringResource(R.string.ai_identify_characters_hint),
                     color = LegadoTheme.colorScheme.onSurfaceVariant
                 )
             }
 
-            else -> AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+            else -> Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                 sheet.candidates.forEach { candidate ->
                     CharacterIdentifyCandidateRow(candidate, onIntent)
                 }
@@ -251,7 +245,7 @@ private fun CharacterIdentifyCandidateRow(
     onIntent: (CharacterListIntent) -> Unit,
 ) {
     val expanded = rememberSaveable(candidate.id) { mutableStateOf(false) }
-    AppColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) {
+    Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
         CheckboxItem(
             title = candidate.name,
             checked = candidate.selected,
@@ -277,10 +271,10 @@ private fun CharacterIdentifyCandidateRow(
                     tint = LegadoTheme.colorScheme.onSurfaceVariant,
                 )
             }
-            AnimatedVisibility(
+            androidx.compose.animation.AnimatedVisibility(
                 visible = expanded.value,
-                enter = expandVertically() + fadeIn(),
-                exit = shrinkVertically() + fadeOut(),
+                enter = androidx.compose.animation.expandVertically() + androidx.compose.animation.fadeIn(),
+                exit = androidx.compose.animation.shrinkVertically() + androidx.compose.animation.fadeOut(),
             ) {
                 AnimatedTextLine(
                     candidate.summary,
@@ -379,7 +373,7 @@ private fun CharacterListItem(
                     )
                 }
             }
-            AppColumn(
+            Column(
                 modifier = Modifier.weight(1f),
                 verticalArrangement = Arrangement.spacedBy(2.dp),
             ) {

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/knowledge/BookCharacterNetworkScreen.kt

@@ -41,7 +41,6 @@ import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
@@ -191,7 +190,7 @@ private fun CharacterNodeStrip(
     characters: List<CharacterNodeUi>,
     onOpenCharacter: (String) -> Unit,
 ) {
-    AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
         AppText(
             text = stringResource(R.string.book_characters),
             style = LegadoTheme.typography.titleMedium,
@@ -256,7 +255,7 @@ private fun AddRelationCard(
         modifier = Modifier.fillMaxWidth(),
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(8.dp),
         ) {
@@ -323,7 +322,7 @@ private fun RelationEditorCard(
         modifier = Modifier.fillMaxWidth(),
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(8.dp),
         ) {

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/knowledge/BookEventDetailScreen.kt

@@ -21,7 +21,6 @@ import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
 import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
@@ -100,7 +99,7 @@ private fun EventDetailContent(
     onIntent: (EventDetailIntent) -> Unit,
     modifier: Modifier = Modifier,
 ) {
-    AppColumn(
+    Column(
         modifier = modifier.padding(horizontal = 16.dp, vertical = 12.dp),
         verticalArrangement = Arrangement.spacedBy(12.dp),
     ) {

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/knowledge/BookEventListScreen.kt

@@ -27,7 +27,6 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.card.GlassCard
@@ -152,7 +151,7 @@ private fun EventEntryCard(
         onClick = onClick,
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/knowledge/BookKnowledgeDetailScreen.kt

@@ -29,7 +29,6 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.card.GlassCard
@@ -145,7 +144,7 @@ private fun KnowledgeDetailContent(
     onIntent: (KnowledgeDetailIntent) -> Unit,
     modifier: Modifier = Modifier,
 ) {
-    AppColumn(
+    Column(
         modifier = modifier.padding(horizontal = 16.dp, vertical = 12.dp),
         verticalArrangement = Arrangement.spacedBy(12.dp),
     ) {
@@ -196,7 +195,7 @@ private fun KnowledgeTypeSelector(
     var showDropdown by remember { mutableStateOf(false) }
     val currentLabel = KNOWLEDGE_TYPE_LABELS[selectedType]?.let { stringResource(it) } ?: "—"
 
-    AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
         AppText(
             text = stringResource(R.string.knowledge_type),
             style = LegadoTheme.typography.titleMedium,

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/knowledge/BookKnowledgeListScreen.kt

@@ -27,7 +27,6 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.card.GlassCard
@@ -152,7 +151,7 @@ private fun KnowledgeEntryCard(
         onClick = onClick,
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/knowledge/CharacterAvatarCropDialog.kt

@@ -32,7 +32,6 @@ import androidx.compose.ui.unit.dp
 import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import kotlin.math.roundToInt
 
@@ -71,7 +70,7 @@ fun CharacterAvatarCropDialog(
         dismissText = stringResource(R.string.cancel),
         onDismiss = onDismissRequest,
         content = {
-            AppColumn(
+            Column(
                 verticalArrangement = Arrangement.spacedBy(12.dp),
             ) {
                 BoxWithConstraints(

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/knowledge/KnowledgeSharedComponents.kt

@@ -26,7 +26,6 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.card.GlassCard
@@ -55,7 +54,7 @@ fun KnowledgeEditFieldCard(
         modifier = modifier,
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(16.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp)
         ) {
@@ -113,7 +112,7 @@ fun KnowledgeFlowTagEditor(
     var removeTagIndex by remember { mutableStateOf(-1) }
     var removeTagName by remember { mutableStateOf("") }
 
-    AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
         AppText(
             text = title,
             style = LegadoTheme.typography.titleMedium,

+ 12 - 22
app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageScreen.kt

@@ -79,7 +79,6 @@ import io.legado.app.ui.theme.LegadoTheme.composeEngine
 import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.theme.adaptiveContentPadding
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButtonMenu
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.FabMenuItem
@@ -710,8 +709,8 @@ private fun BookshelfManageScreen(
                         onLongClick = { toggleBookSelection(book) },
                         containerColor = animatedContainerColor
                     ) {
-                        AppColumn(
-                            Modifier
+                        Column(
+                            modifier = Modifier
                                 .fillMaxWidth()
                                 .adaptiveHorizontalPadding(vertical = 12.dp),
                             verticalArrangement = Arrangement.SpaceBetween
@@ -735,15 +734,10 @@ private fun BookshelfManageScreen(
                                     )
                                     AppText(
                                         text = "${groupNameResolver(book)} | ${book.originName.ifBlank { book.origin }}",
-                                        style = LegadoTheme.typography.labelSmallEmphasized.copy(
-                                            color = LegadoTheme.colorScheme.primary
-                                        )
+                                        style = LegadoTheme.typography.labelSmallEmphasized.copy(color = LegadoTheme.colorScheme.primary)
                                     )
                                     if (exportMsg != null) {
-                                        AppText(
-                                            text = exportMsg,
-                                            modifier = Modifier.padding(top = 2.dp)
-                                        )
+                                        AppText(text = exportMsg, modifier = Modifier.padding(top = 2.dp))
                                     }
                                 }
                                 TextCard(
@@ -814,11 +808,7 @@ private fun BookshelfManageScreen(
                                     SmallTonalButton(
                                         onClick = {
                                             if (!book.isLocal) {
-                                                viewModel.dispatch(
-                                                    BookshelfManageScreenIntent.ToggleBookDownload(
-                                                        book
-                                                    )
-                                                )
+                                                viewModel.dispatch(BookshelfManageScreenIntent.ToggleBookDownload(book))
                                             }
                                         },
                                         icon = if (isDownloading) Icons.Default.Stop else Icons.Default.Download,
@@ -958,7 +948,7 @@ private fun BookshelfManageScreen(
         },
         title = stringResource(R.string.change_source_batch),
         content = {
-            AppColumn(
+            Column(
                 modifier = Modifier.fillMaxWidth(),
                 horizontalAlignment = Alignment.CenterHorizontally,
                 verticalArrangement = Arrangement.spacedBy(12.dp),
@@ -1019,7 +1009,7 @@ private fun BookshelfManageScreen(
         onDismissRequest = { showDeleteBookConfirmDialog = false },
         title = stringResource(R.string.draw),
         content = {
-            AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                 AppText(text = stringResource(R.string.sure_del))
                 if (hasLocalBookInDeleteTarget) {
                     Row(
@@ -1118,7 +1108,7 @@ private fun BookshelfManageScreen(
         onDismissRequest = { showExportFileNameDialog = false },
         title = stringResource(R.string.export_file_name),
         content = {
-            AppColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                 AppText(text = exportFileNameHelpText)
                 AppTextField(
                     value = exportFileNameInput,
@@ -1179,7 +1169,7 @@ private fun BookshelfManageScreen(
         content = {
             val episodeTemplateValid = customEpisodeExportNameInput.isNotBlank()
                 && tryParesExportFileName(customEpisodeExportNameInput)
-            AppColumn(verticalArrangement = Arrangement.spacedBy(12.dp)) {
+            Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                 Row(
                     modifier = Modifier.fillMaxWidth(),
                     horizontalArrangement = Arrangement.spacedBy(8.dp)
@@ -1508,8 +1498,8 @@ private fun BatchChangePreviewRow(
         modifier = Modifier.fillMaxWidth(),
         containerColor = LegadoTheme.colorScheme.onSheetContent,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(12.dp),
@@ -1592,7 +1582,7 @@ private fun PreviewBookInfo(
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
 ) {
-    AppColumn(
+    Column(
         modifier = modifier.clickable(enabled = book != null, onClick = onClick),
         verticalArrangement = Arrangement.spacedBy(6.dp),
         horizontalAlignment = Alignment.CenterHorizontally,

+ 29 - 25
app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt

@@ -166,7 +166,6 @@ import io.legado.app.ui.book.read.sheet.ReadStyleContent
 import io.legado.app.ui.book.read.sheet.ReadStyleTextTitleContent
 import io.legado.app.ui.book.read.sheet.readMenuButtonInfos
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppSlider
 import io.legado.app.ui.widget.components.AppVerticalSlider
 import io.legado.app.ui.widget.components.button.series.SmallTonalButton
@@ -251,8 +250,7 @@ fun ReadBookMenuBar(
             exit = slideOutVertically(targetOffsetY = { -it }) + fadeOut(),
             modifier = Modifier.align(Alignment.TopCenter),
         ) {
-            AppColumn(
-            ) {
+            Column {
                 MenuTitleBar(
                     state = state,
                     colors = menuColors,
@@ -373,7 +371,7 @@ fun ReadBookMenuBar(
             exit = slideOutVertically(targetOffsetY = { it }) + fadeOut(),
             modifier = Modifier.align(Alignment.BottomCenter),
         ) {
-            AppColumn(horizontalAlignment = Alignment.CenterHorizontally) {
+            Column(horizontalAlignment = Alignment.CenterHorizontally) {
                 if (state.menuVisible &&
                     state.menuConfig.showTitleBarIcons &&
                     state.menuConfig.titleBarIconPosition >= 2
@@ -866,12 +864,12 @@ private fun ReadBookMenuRoutePage(
     onBack: () -> Unit,
     content: @Composable () -> Unit,
 ) {
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .heightIn(max = maxHeight)
             .let { if (animateSize) it.animateContentSize() else it }
-            .padding(top = 16.dp, bottom = 16.dp + bottomPadding)
+            .padding(top = 16.dp, bottom = 16.dp + bottomPadding),
     ) {
         Row(
             modifier = Modifier
@@ -957,8 +955,8 @@ private fun MenuTitleBar(
         )
     )
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .then(
                 if (useTopBarBlur && hazeState != null) {
@@ -1012,6 +1010,8 @@ private fun MenuTitleBar(
     ) {
         val useTitleCapsule = readMenuTopBarTitleCapsuleEnabled(backdrop, state.menuConfig)
         val capsuleIconColor = LegadoTheme.colorScheme.onSurfaceVariant
+
+        // Title row: left group (back + capsule/title) + right group (actions)
         Row(
             modifier = Modifier
                 .fillMaxWidth()
@@ -1141,6 +1141,8 @@ private fun MenuTitleBar(
                 }
             }
         }
+
+        // Book name on its own line (mode "1") — hidden when capsule is active
         if (titleBarMode == "1" && !useTitleCapsule) {
             AppText(
                 text = state.bookName,
@@ -1160,6 +1162,8 @@ private fun MenuTitleBar(
                 overflow = TextOverflow.Ellipsis,
             )
         }
+
+        // Chapter name + source action (modes "0" and "1") — hidden when capsule is active
         if ((titleBarMode == "0" || titleBarMode == "1") && !useTitleCapsule) {
             Row(
                 modifier = Modifier
@@ -1464,8 +1468,8 @@ private fun RowScope.TitleCapsuleGlassLayout(
             .padding(horizontal = 12.dp),
         verticalAlignment = Alignment.CenterVertically,
     ) {
-        AppColumn(
-            Modifier.weight(1f)
+        Column(
+            modifier = Modifier.weight(1f),
         ) {
             AppText(
                 text = state.bookName,
@@ -2278,14 +2282,14 @@ private fun SearchBottomMenuContent(
         0
     }
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .windowInsetsPadding(
                 WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)
             )
             .padding(top = 12.dp, bottom = bottomPadding)
-            .animateContentSize()
+            .animateContentSize(),
     ) {
         Column(
             modifier = Modifier
@@ -2432,11 +2436,7 @@ private fun MenuBottomBar(
 ) {
     val seekMax = state.seekMax.coerceAtLeast(0)
     val sliderMax = seekMax.toFloat().coerceAtLeast(1f)
-    var sliderValue by remember {
-        mutableFloatStateOf(
-            state.seekProgress.coerceIn(0, seekMax).toFloat()
-        )
-    }
+    var sliderValue by remember { mutableFloatStateOf(state.seekProgress.coerceIn(0, seekMax).toFloat()) }
     var sliderDragging by remember { mutableStateOf(false) }
     var previewPageIndex by remember { mutableIntStateOf(state.seekProgress.coerceIn(0, seekMax)) }
     val toolButtonsBottomPadding = if (buttonGlassEnabled) 6.dp else 0.dp
@@ -2490,14 +2490,14 @@ private fun MenuBottomBar(
         }
     }
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .windowInsetsPadding(
                 WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)
             )
             .padding(top = 8.dp, bottom = contentBottomPadding)
-            .animateContentSize()
+            .animateContentSize(),
     ) {
         if (state.menuConfig.showBrightnessView == "1") {
             BrightnessBar(
@@ -2520,6 +2520,8 @@ private fun MenuBottomBar(
             )
             Spacer(Modifier.height(4.dp))
         }
+
+        // Seek bar row: prev + slider + next
         AnimatedVisibility(visible = state.menuConfig.readSliderMode != "1") {
             Row(
                 modifier = Modifier
@@ -2571,6 +2573,8 @@ private fun MenuBottomBar(
         }
 
         Spacer(Modifier.height(12.dp))
+
+        // Tool buttons
         val toolButtons = remember(
             context,
             state.menuConfig.bottomBarButtons,
@@ -2937,7 +2941,7 @@ private fun ToolButtonItem(
         else -> null
     }
 
-    AppColumn(
+    Column(
         modifier = modifier,
         horizontalAlignment = Alignment.CenterHorizontally
     ) {
@@ -3483,8 +3487,8 @@ private fun BrightnessBar(
     )
 
     if (vertical) {
-        AppColumn(
-            modifier
+        Column(
+            modifier = modifier
                 .width(if (buttonGlassEnabled) 64.dp else 56.dp)
                 .padding(vertical = 12.dp, horizontal = 4.dp),
             horizontalAlignment = Alignment.CenterHorizontally,

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/read/TextActionSelectionMenu.kt

@@ -63,7 +63,6 @@ import androidx.compose.ui.window.PopupProperties
 import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.text.AppText
 import kotlin.math.roundToInt
@@ -422,8 +421,8 @@ private fun MoreMenuView(
 ) {
     val scrollState = rememberScrollState()
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .width(IntrinsicSize.Max)
     ) {
         Box(

+ 5 - 8
app/src/main/java/io/legado/app/ui/book/read/sheet/AiRewritePresetConfigSheet.kt

@@ -25,7 +25,6 @@ import io.legado.app.ui.book.read.AiRewritePresetConfigUiState
 import io.legado.app.ui.book.read.AiRewritePresetUi
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
@@ -46,8 +45,8 @@ fun AiRewritePresetConfigSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.ai_rewrite_presets),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
         ) {
             Row(
@@ -130,8 +129,8 @@ private fun PresetEditor(
         modifier = Modifier.fillMaxWidth(),
         containerColor = LegadoTheme.colorScheme.surfaceContainerHigh,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(10.dp),
@@ -178,9 +177,7 @@ private fun PresetItem(
             verticalAlignment = Alignment.CenterVertically,
             horizontalArrangement = Arrangement.spacedBy(8.dp),
         ) {
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
                 AppText(
                     text = preset.name,
                     style = LegadoTheme.typography.labelLargeEmphasized,

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/AiTextCleanSheet.kt

@@ -23,7 +23,6 @@ import io.legado.app.ui.ai.chat.AiGeneratedMessageContent
 import io.legado.app.ui.book.read.AiTextCleanUiState
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 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
@@ -46,10 +45,10 @@ fun AiTextCleanSheet(
         },
         title = stringResource(R.string.ai_text_clean),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
-                .padding(bottom = 24.dp)
+                .padding(bottom = 24.dp),
         ) {
             Column(
                 modifier = Modifier

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

@@ -38,7 +38,6 @@ import io.legado.app.ui.book.read.AiRewritePresetUi
 import io.legado.app.ui.book.read.AiTextRewriteUiState
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppRadioButton
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.EmptyMessage
@@ -93,9 +92,9 @@ fun AiTextRewriteSheet(
             )
         }
     ) {
-        AppColumn(
-            Modifier
-                .fillMaxWidth()
+        Column(
+            modifier = Modifier
+                .fillMaxWidth(),
         ) {
             Column(
                 modifier = Modifier
@@ -313,8 +312,8 @@ private fun RewriteHistoryItem(
         onClick = if (enabled) onSelect else null,
         containerColor = LegadoTheme.colorScheme.surfaceContainerHigh,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(12.dp),
             verticalArrangement = Arrangement.spacedBy(8.dp),
@@ -403,9 +402,7 @@ private fun RewritePresetOption(
                 onClick = onSelect,
                 enabled = enabled,
             )
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
                 AppText(
                     text = preset.name,
                     style = LegadoTheme.typography.labelLargeEmphasized,
@@ -438,9 +435,7 @@ private fun CollapsibleTextPreview(
         modifier = Modifier.fillMaxWidth(),
         containerColor = LegadoTheme.colorScheme.surfaceContainerHigh,
     ) {
-        AppColumn(
-            Modifier.padding(16.dp)
-        ) {
+        Column(modifier = Modifier.padding(16.dp)) {
             SelectionContainer {
                 AppText(
                     text = text,

+ 7 - 6
app/src/main/java/io/legado/app/ui/book/read/sheet/AutoReadSheet.kt

@@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.FilledTonalIconButton
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
@@ -28,7 +27,6 @@ import io.legado.app.data.repository.ReadPreferences
 import io.legado.app.data.repository.ReadSettingsRepository
 import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.TinySliderSettingItem
 import org.koin.compose.koinInject
@@ -81,9 +79,10 @@ fun AutoReadContent(
         speed = preferences.autoReadSpeed.coerceIn(1, 120).toFloat()
     }
 
-    AppColumn(
-        modifier.fillMaxWidth()
+    Column(
+        modifier = modifier.fillMaxWidth(),
     ) {
+        // Speed display
         Row(
             modifier = Modifier.fillMaxWidth(),
             horizontalArrangement = Arrangement.Center,
@@ -116,6 +115,8 @@ fun AutoReadContent(
         )
 
         Spacer(Modifier.height(12.dp))
+
+        // Action buttons
         Row(
             modifier = Modifier.fillMaxWidth(),
             horizontalArrangement = Arrangement.SpaceEvenly,
@@ -154,10 +155,10 @@ private fun ActionButton(
     label: String,
     onClick: () -> Unit,
 ) {
-    AppColumn(
+    Column(
         horizontalAlignment = Alignment.CenterHorizontally,
     ) {
-        FilledTonalIconButton(onClick = onClick) {
+        androidx.compose.material3.FilledTonalIconButton(onClick = onClick) {
             Icon(
                 painter = painterResource(icon),
                 contentDescription = label,

+ 7 - 5
app/src/main/java/io/legado/app/ui/book/read/sheet/BgTextConfigSheet.kt

@@ -43,7 +43,6 @@ import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.book.read.ReadBookStyleConfig
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
@@ -94,12 +93,13 @@ fun BgTextConfigSheet(
         title = styleName,
         contentWindowInsets = { WindowInsets.navigationBars },
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 16.dp)
-                .verticalScroll(rememberScrollState())
+                .verticalScroll(rememberScrollState()),
         ) {
+            // Action buttons row
             Row(
                 modifier = Modifier.fillMaxWidth(),
                 horizontalArrangement = Arrangement.spacedBy(4.dp),
@@ -184,6 +184,8 @@ fun BgTextConfigSheet(
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BgAlpha(it.toInt())))
                 },
             )
+
+            // TODO: Add background image grid from assets
         }
     }
 
@@ -285,7 +287,7 @@ private fun ActionCard(
         modifier = modifier,
         containerColor = if (enabled) LegadoTheme.colorScheme.surfaceContainerLow else LegadoTheme.colorScheme.surfaceContainerLow.copy(alpha = 0.5f),
     ) {
-        AppColumn(
+        Column(
             horizontalAlignment = Alignment.CenterHorizontally,
             verticalArrangement = Arrangement.Center,
             modifier = Modifier

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/read/sheet/ChangeChapterSourceSheet.kt

@@ -36,7 +36,6 @@ import io.legado.app.ui.book.changesource.ChangeChapterSourceIntent
 import io.legado.app.ui.book.changesource.ChangeChapterSourceUiState
 import io.legado.app.ui.book.search.ScopeSelectSheet
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.EmptyMessage
 import io.legado.app.ui.widget.components.button.series.MediumPlainButton
@@ -272,7 +271,7 @@ private fun SearchContent(
                         )
                     },
                     supportingContent = {
-                        AppColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) {
+                        Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
                             AppText(
                                 text = item.author,
                                 style = LegadoTheme.typography.labelLargeEmphasized

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/ChapterSummarySheet.kt

@@ -22,7 +22,6 @@ import io.legado.app.ui.ai.chat.AiGeneratedMessageContent
 import io.legado.app.ui.book.read.ChapterSummaryUiState
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.button.series.SmallTonalButton
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
@@ -46,8 +45,8 @@ fun ChapterSummarySheet(
     ) {
         when {
             state.errorMessage != null -> {
-                AppColumn(
-                    Modifier
+                Column(
+                    modifier = Modifier
                         .fillMaxWidth()
                         .padding(bottom = 24.dp),
                     horizontalAlignment = Alignment.CenterHorizontally,
@@ -94,7 +93,7 @@ fun ChapterSummarySheet(
                         .height(240.dp),
                     contentAlignment = Alignment.Center,
                 ) {
-                    AppColumn(horizontalAlignment = Alignment.CenterHorizontally) {
+                    Column(horizontalAlignment = Alignment.CenterHorizontally) {
                         AppCircularProgressIndicator()
                         Spacer(Modifier.height(16.dp))
                         AppText(

+ 1 - 3
app/src/main/java/io/legado/app/ui/book/read/sheet/CharsetConfigSheet.kt

@@ -22,7 +22,6 @@ import io.legado.app.R
 import io.legado.app.constant.AppConst
 import io.legado.app.model.ReadBook
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -38,8 +37,7 @@ fun CharsetConfigSheet(
         containerColor = LegadoTheme.colorScheme.surfaceContainer,
         title = { Text(stringResource(R.string.set_charset)) },
         text = {
-            AppColumn(
-            ) {
+            Column {
                 ExposedDropdownMenuBox(
                     expanded = expanded,
                     onExpandedChange = { expanded = it },

+ 4 - 6
app/src/main/java/io/legado/app/ui/book/read/sheet/ClickActionConfigSheet.kt

@@ -27,7 +27,6 @@ import io.legado.app.constant.PreferKey
 import io.legado.app.data.repository.ReadPreferences
 import io.legado.app.data.repository.ReadSettingsRepository
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.text.AppText
@@ -72,10 +71,10 @@ fun ClickActionConfigSheet(
             .background(LegadoTheme.colorScheme.surfaceContainerLow.copy(alpha = 0.4f))
             .clickable(onClick = onDismissRequest),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxSize()
-                .padding(12.dp)
+                .padding(12.dp),
         ) {
             Spacer(
                 modifier = Modifier.padding(top = 36.dp)
@@ -181,8 +180,7 @@ fun ClickActionConfigSheet(
         onDismissRequest = { selectingPrefKey = null },
         title = stringResource(R.string.select_action),
         content = {
-            AppColumn(
-            ) {
+            Column {
                 actionValues.forEachIndexed { index, label ->
                     AppText(
                         text = label,

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/ContentEditSheet.kt

@@ -30,7 +30,6 @@ import io.legado.app.R
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.book.read.ReadBookUiState
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
 import io.legado.app.ui.widget.components.checkBox.AppCheckbox
@@ -122,10 +121,10 @@ fun ContentEditSheet(
             )
         },
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
-                .padding(bottom = 16.dp)
+                .padding(bottom = 16.dp),
         ) {
             if (state.contentEditLoading) {
                 Box(

+ 4 - 6
app/src/main/java/io/legado/app/ui/book/read/sheet/ContentProcessesSheet.kt

@@ -31,7 +31,6 @@ import io.legado.app.ui.book.read.ContentProcessConfigUiState
 import io.legado.app.ui.book.read.ContentProcessItemUi
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.button.series.MediumToggleButton
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
@@ -114,8 +113,7 @@ fun ContentProcessesSheet(
                         onDismissRequest = { viewingItem = null },
                         title = contentProcessTitle(item),
                         content = {
-                            AppColumn(
-                            ) {
+                            Column {
                                 AppText(
                                     text = stringResource(R.string.ai_text_clean_before),
                                     style = LegadoTheme.typography.labelSmall,
@@ -176,10 +174,10 @@ private fun ContentProcessItem(
         onClick = onClick,
         containerColor = LegadoTheme.colorScheme.onSheetContent,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
-                .padding(12.dp)
+                .padding(12.dp),
         ) {
             Row(
                 modifier = Modifier.fillMaxWidth(),

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/read/sheet/DownloadSheet.kt

@@ -19,7 +19,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.model.ReadBook
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 
 @Composable
 fun DownloadSheet(
@@ -35,7 +34,7 @@ fun DownloadSheet(
         containerColor = LegadoTheme.colorScheme.surfaceContainer,
         title = { Text(stringResource(R.string.offline_cache)) },
         text = {
-            AppColumn {
+            androidx.compose.foundation.layout.Column {
                 OutlinedTextField(
                     value = startChapter,
                     onValueChange = { startChapter = it },

+ 3 - 6
app/src/main/java/io/legado/app/ui/book/read/sheet/EffectiveReplacesSheet.kt

@@ -26,7 +26,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.data.entities.ReplaceRule
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.icon.AppIcon
@@ -105,9 +104,7 @@ fun EffectiveReplacesSheet(
                                 .padding(horizontal = 12.dp, vertical = 8.dp),
                             verticalAlignment = Alignment.CenterVertically,
                         ) {
-                            AppColumn(
-                                Modifier.weight(1f)
-                            ) {
+                            Column(modifier = Modifier.weight(1f)) {
                                 AppText(
                                     text = if (rule.id == RE_SEGMENT_ID) {
                                         stringResource(R.string.re_segment)
@@ -159,8 +156,8 @@ fun EffectiveReplacesSheet(
                                         else -> onDisableRule(rule)
                                     }
                                 },
-                                icon = Icons.Default.Close,
-                                contentDescription = stringResource(R.string.close)
+                icon = Icons.Default.Close,
+                contentDescription = stringResource(R.string.close)
                             )
                         }
                     }

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/EyeProtectionConfigSheet.kt

@@ -15,7 +15,6 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.dialog.TimePickerDialog
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
@@ -53,11 +52,11 @@ fun EyeProtectionConfigSheet(
         title = stringResource(R.string.eye_protection),
         animateContentSize = false,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .verticalScroll(rememberScrollState())
-                .padding(bottom = 16.dp)
+                .padding(bottom = 16.dp),
         ) {
             SwitchSettingItem(
                 title = stringResource(R.string.eye_protection_enabled),

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/FloatingBarIconConfigSheet.kt

@@ -41,7 +41,6 @@ import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookButtonConfigItem
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 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
@@ -122,10 +121,10 @@ private fun ButtonIconConfigSheet(
         onDismissRequest = onDismissRequest,
         title = title,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
-                .padding(bottom = 16.dp)
+                .padding(bottom = 16.dp),
         ) {
             LazyColumn(
                 state = lazyListState,

+ 5 - 10
app/src/main/java/io/legado/app/ui/book/read/sheet/GlobalThemePage.kt

@@ -60,7 +60,6 @@ import io.legado.app.ui.book.read.ReadBookSheet
 import io.legado.app.ui.book.read.ReadBookStyleConfig
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.fadingEdge
-import io.legado.app.ui.widget.components.AppColumn
 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.card.TextCard
@@ -94,8 +93,8 @@ fun GlobalThemePage(
 
     val configList = styleConfig.styleItems
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
             .verticalScroll(rememberScrollState())
     ) {
@@ -135,6 +134,8 @@ fun GlobalThemePage(
         }
 
         Spacer(Modifier.height(4.dp))
+
+        // Style section label + Day/Night
         NormalCard(
             containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
             cornerRadius = 12.dp
@@ -207,13 +208,7 @@ fun GlobalThemePage(
                     NormalCard(
                         onClick = {
                             val newShareLayout = !shareLayout
-                            onIntent(
-                                ReadBookIntent.UpdateConfig(
-                                    ConfigUpdate.ShareLayout(
-                                        newShareLayout
-                                    )
-                                )
-                            )
+                            onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShareLayout(newShareLayout)))
                             onShareLayoutChange(newShareLayout)
                         },
                         modifier = Modifier

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

@@ -50,7 +50,6 @@ import io.legado.app.help.config.ReadBookConfig
 import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.FontFolderState
 import io.legado.app.ui.widget.components.FontSelectSheet
 import io.legado.app.ui.widget.components.dialog.CustomTipDialog
@@ -201,27 +200,22 @@ internal fun HeaderFooterPage(
                 headerLeft = value
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderLeft(value)))
             }
-
             CustomTipTarget.HEADER_MIDDLE -> {
                 headerMiddle = value
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderMiddle(value)))
             }
-
             CustomTipTarget.HEADER_RIGHT -> {
                 headerRight = value
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipHeaderRight(value)))
             }
-
             CustomTipTarget.FOOTER_LEFT -> {
                 footerLeft = value
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterLeft(value)))
             }
-
             CustomTipTarget.FOOTER_MIDDLE -> {
                 footerMiddle = value
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterMiddle(value)))
             }
-
             CustomTipTarget.FOOTER_RIGHT -> {
                 footerRight = value
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TipFooterRight(value)))
@@ -250,8 +244,8 @@ internal fun HeaderFooterPage(
         }
     }
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
     ) {
         CardTabRow(
@@ -264,10 +258,7 @@ internal fun HeaderFooterPage(
                     try {
                         pagerState.animateScrollToPage(
                             page = index,
-                            animationSpec = tween(
-                                durationMillis = 300,
-                                easing = FastOutSlowInEasing
-                            )
+                            animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing)
                         )
                     } finally {
                         clickScrollCount = (clickScrollCount - 1).coerceAtLeast(0)
@@ -293,432 +284,320 @@ internal fun HeaderFooterPage(
                     }
             ) {
                 when (page) {
-                    0 -> {
-                        // Header tab
-                        Column(
-                            modifier = Modifier
-                                .fillMaxWidth()
-                                .padding(horizontal = 16.dp)
-                                .verticalScroll(headerScrollState),
-                        ) {
-                            TinySwitchSettingItem(
-                                title = stringResource(R.string.showLine),
-                                checked = showHeaderLine,
-                                onCheckedChange = {
-                                    showHeaderLine = it
-                                    onIntent(
-                                        ReadBookIntent.UpdateConfig(
-                                            ConfigUpdate.ShowHeaderLine(
-                                                it
-                                            )
-                                        )
-                                    )
-                                },
-                            )
-                            val headerModes = ReadBookConfig.getHeaderModes(context)
-                            TinyDropdownSettingItem(
-                                title = stringResource(R.string.header),
-                                selectedValue = headerMode.toString(),
-                                displayEntries = headerModes.values.toTypedArray(),
-                                entryValues = headerModes.keys.map { it.toString() }.toTypedArray(),
-                                onValueChange = {
-                                    headerMode = it.toInt()
-                                    onIntent(
-                                        ReadBookIntent.UpdateConfig(
-                                            ConfigUpdate.HeaderMode(
-                                                headerMode
-                                            )
-                                        )
-                                    )
-                                },
-                            )
-                            TipPositionDropdown(
-                                label = stringResource(R.string.left),
-                                value = headerLeft,
-                                tipNames = tipNames,
-                                tipValues = tipValues,
-                                onValueChange = {
-                                    handleTipChange(
-                                        CustomTipTarget.HEADER_LEFT,
-                                        it
-                                    )
-                                },
-                            )
-                            TipPositionDropdown(
-                                label = stringResource(R.string.middle),
-                                value = headerMiddle,
-                                tipNames = tipNames,
-                                tipValues = tipValues,
-                                onValueChange = {
-                                    handleTipChange(
-                                        CustomTipTarget.HEADER_MIDDLE,
-                                        it
-                                    )
-                                },
-                            )
-                            TipPositionDropdown(
-                                label = stringResource(R.string.right),
-                                value = headerRight,
-                                tipNames = tipNames,
-                                tipValues = tipValues,
-                                onValueChange = {
-                                    handleTipChange(
-                                        CustomTipTarget.HEADER_RIGHT,
-                                        it
-                                    )
-                                },
-                            )
-                            TinyColorModeSettingItem(
-                                title = stringResource(R.string.header_color),
-                                dayColor = if (ReadBookConfig.tipHeaderColor != 0) {
-                                    ReadBookConfig.tipHeaderColor
-                                } else {
-                                    ReadBookConfig.textColor
-                                },
-                                nightColor = if (ReadBookConfig.tipHeaderColorNight != 0) {
-                                    ReadBookConfig.tipHeaderColorNight
+                0 -> {
+                    // Header tab
+                    Column(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(horizontal = 16.dp)
+                            .verticalScroll(headerScrollState),
+                    ) {
+                        TinySwitchSettingItem(
+                            title = stringResource(R.string.showLine),
+                            checked = showHeaderLine,
+                            onCheckedChange = {
+                                showHeaderLine = it
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShowHeaderLine(it)))
+                            },
+                        )
+                        val headerModes = ReadBookConfig.getHeaderModes(context)
+                        TinyDropdownSettingItem(
+                            title = stringResource(R.string.header),
+                            selectedValue = headerMode.toString(),
+                            displayEntries = headerModes.values.toTypedArray(),
+                            entryValues = headerModes.keys.map { it.toString() }.toTypedArray(),
+                            onValueChange = {
+                                headerMode = it.toInt()
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.HeaderMode(headerMode)))
+                            },
+                        )
+                        TipPositionDropdown(
+                            label = stringResource(R.string.left),
+                            value = headerLeft,
+                            tipNames = tipNames,
+                            tipValues = tipValues,
+                            onValueChange = { handleTipChange(CustomTipTarget.HEADER_LEFT, it) },
+                        )
+                        TipPositionDropdown(
+                            label = stringResource(R.string.middle),
+                            value = headerMiddle,
+                            tipNames = tipNames,
+                            tipValues = tipValues,
+                            onValueChange = { handleTipChange(CustomTipTarget.HEADER_MIDDLE, it) },
+                        )
+                        TipPositionDropdown(
+                            label = stringResource(R.string.right),
+                            value = headerRight,
+                            tipNames = tipNames,
+                            tipValues = tipValues,
+                            onValueChange = { handleTipChange(CustomTipTarget.HEADER_RIGHT, it) },
+                        )
+                        TinyColorModeSettingItem(
+                            title = stringResource(R.string.header_color),
+                            dayColor = if (ReadBookConfig.tipHeaderColor != 0) {
+                                ReadBookConfig.tipHeaderColor
+                            } else {
+                                ReadBookConfig.textColor
+                            },
+                            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.textColorNight
-                                },
-                                onClickColor = { isNight ->
-                                    if (isNight) {
-                                        colorPickerId = COLOR_HEADER_NIGHT
-                                        colorPickerInitial =
-                                            if (ReadBookConfig.tipHeaderColorNight != 0) {
-                                                ReadBookConfig.tipHeaderColorNight
-                                            } else {
-                                                ReadBookConfig.textColorNight
-                                            }
+                                    colorPickerId = COLOR_HEADER
+                                    colorPickerInitial = if (ReadBookConfig.tipHeaderColor != 0) {
+                                        ReadBookConfig.tipHeaderColor
                                     } else {
-                                        colorPickerId = COLOR_HEADER
-                                        colorPickerInitial =
-                                            if (ReadBookConfig.tipHeaderColor != 0) {
-                                                ReadBookConfig.tipHeaderColor
-                                            } else {
-                                                ReadBookConfig.textColor
-                                            }
+                                        ReadBookConfig.textColor
                                     }
-                                    showColorPicker = true
-                                },
-                            )
-
-                            TinyClickableSettingItem(
-                                title = stringResource(R.string.padding),
-                                description = stringResource(
-                                    R.string.padding_format,
-                                    headerPaddingTop.toInt(),
-                                    headerPaddingBottom.toInt(),
-                                    headerPaddingLeft.toInt(),
-                                    headerPaddingRight.toInt(),
-                                ),
-                                trailingContent = {
-                                    Icon(
-                                        imageVector = if (expandHeaderPadding) Icons.Default.ExpandMore else Icons.Default.ChevronRight,
-                                        contentDescription = null,
-                                        tint = LegadoTheme.colorScheme.onSurfaceVariant,
-                                        modifier = Modifier.size(20.dp),
-                                    )
-                                },
-                                onClick = {
-                                    expandHeaderPadding = !expandHeaderPadding
-                                },
-                            )
-                            AnimatedVisibility(
-                                visible = expandHeaderPadding,
-                                enter = expandVertically() + fadeIn(),
-                                exit = shrinkVertically() + fadeOut(),
-                            ) {
-                                Column(modifier = Modifier.fillMaxWidth()) {
-                                    PaddingSliders(
-                                        top = headerPaddingTop, bottom = headerPaddingBottom,
-                                        left = headerPaddingLeft, right = headerPaddingRight,
-                                        onTopChange = {
-                                            headerPaddingTop = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.HeaderPaddingTop(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                        onBottomChange = {
-                                            headerPaddingBottom = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.HeaderPaddingBottom(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                        onLeftChange = {
-                                            headerPaddingLeft = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.HeaderPaddingLeft(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                        onRightChange = {
-                                            headerPaddingRight = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.HeaderPaddingRight(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                    )
                                 }
+                                showColorPicker = true
+                            },
+                        )
+
+                        TinyClickableSettingItem(
+                            title = stringResource(R.string.padding),
+                            description = stringResource(
+                                R.string.padding_format,
+                                headerPaddingTop.toInt(),
+                                headerPaddingBottom.toInt(),
+                                headerPaddingLeft.toInt(),
+                                headerPaddingRight.toInt(),
+                            ),
+                            trailingContent = {
+                                Icon(
+                                    imageVector = if (expandHeaderPadding) Icons.Default.ExpandMore else Icons.Default.ChevronRight,
+                                    contentDescription = null,
+                                    tint = LegadoTheme.colorScheme.onSurfaceVariant,
+                                    modifier = Modifier.size(20.dp),
+                                )
+                            },
+                            onClick = {
+                                expandHeaderPadding = !expandHeaderPadding
+                            },
+                        )
+                        AnimatedVisibility(
+                            visible = expandHeaderPadding,
+                            enter = expandVertically() + fadeIn(),
+                            exit = shrinkVertically() + fadeOut(),
+                        ) {
+                            Column(modifier = Modifier.fillMaxWidth()) {
+                                PaddingSliders(
+                                    top = headerPaddingTop, bottom = headerPaddingBottom,
+                                    left = headerPaddingLeft, right = headerPaddingRight,
+                                    onTopChange = {
+                                        headerPaddingTop = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.HeaderPaddingTop(it.toInt())))
+                                    },
+                                    onBottomChange = {
+                                        headerPaddingBottom = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.HeaderPaddingBottom(it.toInt())))
+                                    },
+                                    onLeftChange = {
+                                        headerPaddingLeft = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.HeaderPaddingLeft(it.toInt())))
+                                    },
+                                    onRightChange = {
+                                        headerPaddingRight = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.HeaderPaddingRight(it.toInt())))
+                                    },
+                                )
                             }
                         }
                     }
+                }
 
-                    1 -> {
-                        // Footer tab
-                        Column(
-                            modifier = Modifier
-                                .fillMaxWidth()
-                                .padding(horizontal = 16.dp)
-                                .verticalScroll(footerScrollState),
-                        ) {
-                            TinySwitchSettingItem(
-                                title = stringResource(R.string.showLine),
-                                checked = showFooterLine,
-                                onCheckedChange = {
-                                    showFooterLine = it
-                                    onIntent(
-                                        ReadBookIntent.UpdateConfig(
-                                            ConfigUpdate.ShowFooterLine(
-                                                it
-                                            )
-                                        )
-                                    )
-                                },
-                            )
-                            val footerModes = ReadBookConfig.getFooterModes(context)
-                            TinyDropdownSettingItem(
-                                title = stringResource(R.string.footer),
-                                selectedValue = footerMode.toString(),
-                                displayEntries = footerModes.values.toTypedArray(),
-                                entryValues = footerModes.keys.map { it.toString() }.toTypedArray(),
-                                onValueChange = {
-                                    footerMode = it.toInt()
-                                    onIntent(
-                                        ReadBookIntent.UpdateConfig(
-                                            ConfigUpdate.FooterMode(
-                                                footerMode
-                                            )
-                                        )
-                                    )
-                                },
-                            )
-                            TipPositionDropdown(
-                                label = stringResource(R.string.left),
-                                value = footerLeft,
-                                tipNames = tipNames,
-                                tipValues = tipValues,
-                                onValueChange = {
-                                    handleTipChange(
-                                        CustomTipTarget.FOOTER_LEFT,
-                                        it
-                                    )
-                                },
-                            )
-                            TipPositionDropdown(
-                                label = stringResource(R.string.middle),
-                                value = footerMiddle,
-                                tipNames = tipNames,
-                                tipValues = tipValues,
-                                onValueChange = {
-                                    handleTipChange(
-                                        CustomTipTarget.FOOTER_MIDDLE,
-                                        it
-                                    )
-                                },
-                            )
-                            TipPositionDropdown(
-                                label = stringResource(R.string.right),
-                                value = footerRight,
-                                tipNames = tipNames,
-                                tipValues = tipValues,
-                                onValueChange = {
-                                    handleTipChange(
-                                        CustomTipTarget.FOOTER_RIGHT,
-                                        it
-                                    )
-                                },
-                            )
-                            TinyColorModeSettingItem(
-                                title = stringResource(R.string.footer_color),
-                                dayColor = if (ReadBookConfig.tipFooterColor != 0) {
-                                    ReadBookConfig.tipFooterColor
-                                } else {
-                                    ReadBookConfig.textColor
-                                },
-                                nightColor = if (ReadBookConfig.tipFooterColorNight != 0) {
-                                    ReadBookConfig.tipFooterColorNight
+                1 -> {
+                    // Footer tab
+                    Column(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(horizontal = 16.dp)
+                            .verticalScroll(footerScrollState),
+                    ) {
+                        TinySwitchSettingItem(
+                            title = stringResource(R.string.showLine),
+                            checked = showFooterLine,
+                            onCheckedChange = {
+                                showFooterLine = it
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShowFooterLine(it)))
+                            },
+                        )
+                        val footerModes = ReadBookConfig.getFooterModes(context)
+                        TinyDropdownSettingItem(
+                            title = stringResource(R.string.footer),
+                            selectedValue = footerMode.toString(),
+                            displayEntries = footerModes.values.toTypedArray(),
+                            entryValues = footerModes.keys.map { it.toString() }.toTypedArray(),
+                            onValueChange = {
+                                footerMode = it.toInt()
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.FooterMode(footerMode)))
+                            },
+                        )
+                        TipPositionDropdown(
+                            label = stringResource(R.string.left),
+                            value = footerLeft,
+                            tipNames = tipNames,
+                            tipValues = tipValues,
+                            onValueChange = { handleTipChange(CustomTipTarget.FOOTER_LEFT, it) },
+                        )
+                        TipPositionDropdown(
+                            label = stringResource(R.string.middle),
+                            value = footerMiddle,
+                            tipNames = tipNames,
+                            tipValues = tipValues,
+                            onValueChange = { handleTipChange(CustomTipTarget.FOOTER_MIDDLE, it) },
+                        )
+                        TipPositionDropdown(
+                            label = stringResource(R.string.right),
+                            value = footerRight,
+                            tipNames = tipNames,
+                            tipValues = tipValues,
+                            onValueChange = { handleTipChange(CustomTipTarget.FOOTER_RIGHT, it) },
+                        )
+                        TinyColorModeSettingItem(
+                            title = stringResource(R.string.footer_color),
+                            dayColor = if (ReadBookConfig.tipFooterColor != 0) {
+                                ReadBookConfig.tipFooterColor
+                            } else {
+                                ReadBookConfig.textColor
+                            },
+                            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.textColorNight
-                                },
-                                onClickColor = { isNight ->
-                                    if (isNight) {
-                                        colorPickerId = COLOR_FOOTER_NIGHT
-                                        colorPickerInitial =
-                                            if (ReadBookConfig.tipFooterColorNight != 0) {
-                                                ReadBookConfig.tipFooterColorNight
-                                            } else {
-                                                ReadBookConfig.textColorNight
-                                            }
+                                    colorPickerId = COLOR_FOOTER
+                                    colorPickerInitial = if (ReadBookConfig.tipFooterColor != 0) {
+                                        ReadBookConfig.tipFooterColor
                                     } else {
-                                        colorPickerId = COLOR_FOOTER
-                                        colorPickerInitial =
-                                            if (ReadBookConfig.tipFooterColor != 0) {
-                                                ReadBookConfig.tipFooterColor
-                                            } else {
-                                                ReadBookConfig.textColor
-                                            }
+                                        ReadBookConfig.textColor
                                     }
-                                    showColorPicker = true
-                                },
-                            )
-
-                            TinyClickableSettingItem(
-                                title = stringResource(R.string.padding),
-                                description = stringResource(
-                                    R.string.padding_format,
-                                    footerPaddingTop.toInt(),
-                                    footerPaddingBottom.toInt(),
-                                    footerPaddingLeft.toInt(),
-                                    footerPaddingRight.toInt(),
-                                ),
-                                trailingContent = {
-                                    Icon(
-                                        imageVector = if (expandFooterPadding) Icons.Default.ExpandMore else Icons.Default.ChevronRight,
-                                        contentDescription = null,
-                                        tint = LegadoTheme.colorScheme.onSurfaceVariant,
-                                        modifier = Modifier.size(20.dp),
-                                    )
-                                },
-                                onClick = {
-                                    expandFooterPadding = !expandFooterPadding
-                                },
-                            )
-                            AnimatedVisibility(
-                                visible = expandFooterPadding,
-                                enter = expandVertically() + fadeIn(),
-                                exit = shrinkVertically() + fadeOut(),
-                            ) {
-                                Column(modifier = Modifier.fillMaxWidth()) {
-                                    PaddingSliders(
-                                        top = footerPaddingTop, bottom = footerPaddingBottom,
-                                        left = footerPaddingLeft, right = footerPaddingRight,
-                                        onTopChange = {
-                                            footerPaddingTop = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.FooterPaddingTop(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                        onBottomChange = {
-                                            footerPaddingBottom = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.FooterPaddingBottom(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                        onLeftChange = {
-                                            footerPaddingLeft = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.FooterPaddingLeft(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                        onRightChange = {
-                                            footerPaddingRight = it
-                                            onIntent(
-                                                ReadBookIntent.UpdateConfig(
-                                                    ConfigUpdate.FooterPaddingRight(
-                                                        it.toInt()
-                                                    )
-                                                )
-                                            )
-                                        },
-                                    )
                                 }
+                                showColorPicker = true
+                            },
+                        )
+
+                        TinyClickableSettingItem(
+                            title = stringResource(R.string.padding),
+                            description = stringResource(
+                                R.string.padding_format,
+                                footerPaddingTop.toInt(),
+                                footerPaddingBottom.toInt(),
+                                footerPaddingLeft.toInt(),
+                                footerPaddingRight.toInt(),
+                            ),
+                            trailingContent = {
+                                Icon(
+                                    imageVector = if (expandFooterPadding) Icons.Default.ExpandMore else Icons.Default.ChevronRight,
+                                    contentDescription = null,
+                                    tint = LegadoTheme.colorScheme.onSurfaceVariant,
+                                    modifier = Modifier.size(20.dp),
+                                )
+                            },
+                            onClick = {
+                                expandFooterPadding = !expandFooterPadding
+                            },
+                        )
+                        AnimatedVisibility(
+                            visible = expandFooterPadding,
+                            enter = expandVertically() + fadeIn(),
+                            exit = shrinkVertically() + fadeOut(),
+                        ) {
+                            Column(modifier = Modifier.fillMaxWidth()) {
+                                PaddingSliders(
+                                    top = footerPaddingTop, bottom = footerPaddingBottom,
+                                    left = footerPaddingLeft, right = footerPaddingRight,
+                                    onTopChange = {
+                                        footerPaddingTop = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.FooterPaddingTop(it.toInt())))
+                                    },
+                                    onBottomChange = {
+                                        footerPaddingBottom = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.FooterPaddingBottom(it.toInt())))
+                                    },
+                                    onLeftChange = {
+                                        footerPaddingLeft = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.FooterPaddingLeft(it.toInt())))
+                                    },
+                                    onRightChange = {
+                                        footerPaddingRight = it
+                                        onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.FooterPaddingRight(it.toInt())))
+                                    },
+                                )
                             }
                         }
                     }
+                }
 
-                    2 -> {
-                        // Global tab
-                        Column(
-                            modifier = Modifier
-                                .fillMaxWidth()
-                                .padding(horizontal = 16.dp)
-                                .verticalScroll(rememberScrollState()),
-                        ) {
-                            SectionTitle(stringResource(R.string.read_config_divider_line))
-                            TinyColorSettingItem(
-                                title = stringResource(R.string.tip_divider_color),
-                                colorValue = when (ReadBookConfig.tipDividerColor) {
+                2 -> {
+                    // Global tab
+                    Column(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(horizontal = 16.dp)
+                            .verticalScroll(rememberScrollState()),
+                    ) {
+                        SectionTitle(stringResource(R.string.read_config_divider_line))
+                        TinyColorSettingItem(
+                            title = stringResource(R.string.tip_divider_color),
+                            colorValue = when (ReadBookConfig.tipDividerColor) {
+                                -1 -> context.getCompatColor(R.color.divider)
+                                0 -> ReadBookConfig.textColor
+                                else -> ReadBookConfig.tipDividerColor
+                            },
+                            onClick = {
+                                colorPickerId = COLOR_DIVIDER
+                                colorPickerInitial = when (ReadBookConfig.tipDividerColor) {
                                     -1 -> context.getCompatColor(R.color.divider)
                                     0 -> ReadBookConfig.textColor
                                     else -> ReadBookConfig.tipDividerColor
-                                },
-                                onClick = {
-                                    colorPickerId = COLOR_DIVIDER
-                                    colorPickerInitial = when (ReadBookConfig.tipDividerColor) {
-                                        -1 -> context.getCompatColor(R.color.divider)
-                                        0 -> ReadBookConfig.textColor
-                                        else -> ReadBookConfig.tipDividerColor
-                                    }
-                                    showColorPicker = true
-                                },
-                            )
-
-                            SectionTitle(stringResource(R.string.text_typeface))
-                            TinyClickableSettingItem(
-                                title = stringResource(R.string.header_font),
-                                description = stringResource(R.string.select_font),
-                                imageVector = Icons.Default.TextFields,
-                                onClick = { showFontSelect = true },
-                            )
-                            TinySliderSettingItem(
-                                title = stringResource(R.string.header_font_size),
-                                value = headerFontSize.toFloat(),
-                                valueRange = 0f..100f,
-                                onValueChange = { value ->
-                                    headerFontSize = value.toInt()
-                                    onIntent(
-                                        ReadBookIntent.UpdateConfig(
-                                            ConfigUpdate.HeaderFontSize(
-                                                value.toInt()
-                                            )
-                                        )
-                                    )
-                                    onIntent(ReadBookIntent.SaveReadStyleConfig)
-                                },
-                            )
-                        }
+                                }
+                                showColorPicker = true
+                            },
+                        )
+
+                        SectionTitle(stringResource(R.string.text_typeface))
+                        TinyClickableSettingItem(
+                            title = stringResource(R.string.header_font),
+                            description = stringResource(R.string.select_font),
+                            imageVector = Icons.Default.TextFields,
+                            onClick = { showFontSelect = true },
+                        )
+                        TinySliderSettingItem(
+                            title = stringResource(R.string.header_font_size),
+                            value = headerFontSize.toFloat(),
+                            valueRange = 0f..100f,
+                            onValueChange = { value ->
+                                headerFontSize = value.toInt()
+                                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.HeaderFontSize(value.toInt())))
+                                onIntent(ReadBookIntent.SaveReadStyleConfig)
+                            },
+                        )
                     }
                 }
             }
         }
     }
+}
 
     // Color picker
     ColorPickerSheet(

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/HighlightRuleConfigSheet.kt

@@ -32,7 +32,6 @@ import io.legado.app.data.entities.HighlightRule
 import io.legado.app.data.repository.configNames
 import io.legado.app.ui.book.read.HighlightRuleConfigUiState
 import io.legado.app.ui.book.read.ReadBookIntent
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.TinySwitch
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.button.series.SmallTonalButton
@@ -165,10 +164,10 @@ fun HighlightRuleConfigSheet(
             }
         },
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
-                .padding(bottom = 16.dp)
+                .padding(bottom = 16.dp),
         ) {
             LazyColumn(
                 state = listState,

+ 20 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/HighlightRuleEditSheet.kt

@@ -50,7 +50,6 @@ import io.legado.app.data.repository.ReadSettingsRepository
 import io.legado.app.data.repository.configNames
 import io.legado.app.data.repository.toJsonArray
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.FontFolderState
 import io.legado.app.ui.widget.components.FontSelectSheet
@@ -237,12 +236,13 @@ fun HighlightRuleEditSheet(
             )
         },
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 16.dp)
-                .verticalScroll(rememberScrollState())
+                .verticalScroll(rememberScrollState()),
         ) {
+            // === Section 1: Rule Info ===
             SectionTitle(stringResource(R.string.rule_info))
 
             AppTextField(
@@ -295,7 +295,11 @@ fun HighlightRuleEditSheet(
                 checked = enabled,
                 onCheckedChange = { enabled = it },
             )
+
+            // === Section 2: Style Settings ===
             SectionTitle(stringResource(R.string.style_settings))
+
+            // Text color
             TinySwitchSettingItem(
                 title = stringResource(R.string.text_color),
                 checked = hasTextColor,
@@ -308,6 +312,8 @@ fun HighlightRuleEditSheet(
                     onClick = { showTextColorPicker = true },
                 )
             }
+
+            // Underline
             TinySwitchSettingItem(
                 title = stringResource(R.string.underline_style),
                 checked = hasUnderline,
@@ -370,6 +376,8 @@ fun HighlightRuleEditSheet(
                     }
                 }
             }
+
+            // Background color
             TinySwitchSettingItem(
                 title = stringResource(R.string.bg_color),
                 checked = hasBgColor,
@@ -382,6 +390,8 @@ fun HighlightRuleEditSheet(
                     onClick = { showBgColorPicker = true },
                 )
             }
+
+            // Background image
             TinySwitchSettingItem(
                 title = stringResource(R.string.highlight_bg_image),
                 checked = hasBgImage,
@@ -421,6 +431,8 @@ fun HighlightRuleEditSheet(
                     )
                 }
             }
+
+            // === Section 3: Config Binding ===
             if (allConfigNames.isNotEmpty()) {
                 SectionTitle("应用排版")
                 LazyRow(
@@ -471,6 +483,8 @@ fun HighlightRuleEditSheet(
                     }
                 }
             }
+
+            // === Section 4: Font ===
             SectionTitle("字体替换")
             TinySwitchSettingItem(
                 title = "自定义字体",
@@ -484,6 +498,8 @@ fun HighlightRuleEditSheet(
                     onClick = { showFontSelect = true },
                 )
             }
+
+            // === Section 5: Preview ===
             SectionTitle(stringResource(R.string.preview_effect))
 
             AppTextField(

+ 8 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/MoreConfigSheet.kt

@@ -18,7 +18,6 @@ import io.legado.app.data.repository.ReadSettingsRepository
 import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.book.read.ReadBookSheet
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.SectionTitle
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.TinyClickableSettingItem
@@ -45,12 +44,13 @@ fun MoreConfigSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.more_setting),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 16.dp)
-                .verticalScroll(rememberScrollState())
+                .verticalScroll(rememberScrollState()),
         ) {
+            // Screen settings
             SectionTitle(stringResource(R.string.screen_settings))
             ScreenSettings(
                 preferences = preferences,
@@ -91,6 +91,8 @@ fun MoreConfigSheet(
                     onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.EyeProtection))
                 }
             )
+
+            // Page control
             SectionTitle(stringResource(R.string.page_control))
             PageControlSettings(
                 preferences = preferences,
@@ -113,6 +115,8 @@ fun MoreConfigSheet(
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.KeyPageOnLongPress(it)))
                 },
             )
+
+            // Other
             SectionTitle(stringResource(R.string.other))
             OtherSettings(
                 preferences = preferences,

+ 3 - 6
app/src/main/java/io/legado/app/ui/book/read/sheet/PaddingConfigSheet.kt

@@ -29,7 +29,6 @@ import io.legado.app.R
 import io.legado.app.ui.book.read.ReadSheetConfigUiState
 import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.pager.pagerHeight
 import io.legado.app.ui.widget.components.pager.rememberPagerAnimatedHeight
@@ -104,8 +103,8 @@ fun PaddingConfigContent(
         }
     }
 
-    AppColumn(
-        modifier.fillMaxWidth()
+    Column(
+        modifier = modifier.fillMaxWidth(),
     ) {
         CardTabRow(
             tabTitles = tabTitles,
@@ -222,9 +221,7 @@ internal fun PaddingSliders(
     onTopChange: (Float) -> Unit, onBottomChange: (Float) -> Unit,
     onLeftChange: (Float) -> Unit, onRightChange: (Float) -> Unit,
 ) {
-    AppColumn(
-        Modifier.fillMaxWidth()
-    ) {
+    Column(modifier = Modifier.fillMaxWidth()) {
         TinySliderSettingItem(
             title = stringResource(R.string.padding_top),
             value = top,

+ 6 - 8
app/src/main/java/io/legado/app/ui/book/read/sheet/PageKeyConfigSheet.kt

@@ -1,6 +1,5 @@
 package io.legado.app.ui.book.read.sheet
 
-import android.view.KeyEvent
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
@@ -30,7 +29,6 @@ import io.legado.app.R
 import io.legado.app.data.repository.ReadPreferences
 import io.legado.app.data.repository.ReadSettingsRepository
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import kotlinx.coroutines.launch
 import org.koin.compose.koinInject
 
@@ -56,8 +54,8 @@ fun PageKeyConfigSheet(
         containerColor = LegadoTheme.colorScheme.surfaceContainer,
         title = { Text(stringResource(R.string.custom_page_key)) },
         text = {
-            AppColumn(
-                modifier = Modifier.verticalScroll(rememberScrollState())
+            Column(
+                modifier = Modifier.verticalScroll(rememberScrollState()),
             ) {
                 OutlinedTextField(
                     value = prevKeys,
@@ -69,8 +67,8 @@ fun PageKeyConfigSheet(
                         .fillMaxWidth()
                         .onKeyEvent { event ->
                             val keyCode = event.nativeKeyEvent.keyCode
-                            if (keyCode != KeyEvent.KEYCODE_BACK &&
-                                keyCode != KeyEvent.KEYCODE_DEL
+                            if (keyCode != android.view.KeyEvent.KEYCODE_BACK &&
+                                keyCode != android.view.KeyEvent.KEYCODE_DEL
                             ) {
                                 prevKeys = if (prevKeys.isEmpty() || prevKeys.endsWith(",")) {
                                     "$prevKeys$keyCode"
@@ -94,8 +92,8 @@ fun PageKeyConfigSheet(
                         .fillMaxWidth()
                         .onKeyEvent { event ->
                             val keyCode = event.nativeKeyEvent.keyCode
-                            if (keyCode != KeyEvent.KEYCODE_BACK &&
-                                keyCode != KeyEvent.KEYCODE_DEL
+                            if (keyCode != android.view.KeyEvent.KEYCODE_BACK &&
+                                keyCode != android.view.KeyEvent.KEYCODE_DEL
                             ) {
                                 nextKeys = if (nextKeys.isEmpty() || nextKeys.endsWith(",")) {
                                     "$nextKeys$keyCode"

+ 4 - 5
app/src/main/java/io/legado/app/ui/book/read/sheet/ReadAloudConfigContent.kt

@@ -39,7 +39,6 @@ import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.book.read.ReadBookUiState
 import io.legado.app.ui.book.readaloud.player.ReadAloudPlayerIntent
 import io.legado.app.ui.book.readaloud.player.ReadAloudPlayerUiState
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.button.series.SmallTonalButton
@@ -68,8 +67,8 @@ fun ReadAloudConfigContent(
 ) {
     val pagerState = rememberPagerState(pageCount = { 2 })
     val scope = rememberCoroutineScope()
-    AppColumn(
-        Modifier.fillMaxWidth()
+    Column(
+        modifier = Modifier.fillMaxWidth(),
     ) {
         CardTabRow(
             modifier = modifier,
@@ -636,8 +635,8 @@ fun ReadAloudNumberConfigSheet(
         onDismissRequest = onDismissRequest,
         title = title,
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 16.dp)
         ) {

+ 5 - 6
app/src/main/java/io/legado/app/ui/book/read/sheet/ReadAloudScreen.kt

@@ -63,7 +63,6 @@ import io.legado.app.ui.book.readaloud.player.ReadAloudPlayerUiState
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.ProvideThemeOverride
 import io.legado.app.ui.theme.ThemeOverrideState
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
@@ -149,8 +148,7 @@ fun ReadAloudScreen(
                 label = "ReadAloudPage",
             ) { targetPage ->
                 when (targetPage) {
-                    ReadAloudPage.Config -> AppColumn(
-                    ) {
+                    ReadAloudPage.Config -> Column {
                         Row(
                             modifier = Modifier
                                 .fillMaxWidth()
@@ -209,9 +207,10 @@ fun ReadAloudContent(
     val ttsSpeechRate = state.readAloudTtsSpeechRate
     var timerMenuExpanded by remember { mutableStateOf(false) }
 
-    AppColumn(
-        modifier.fillMaxWidth()
+    Column(
+        modifier = modifier.fillMaxWidth(),
     ) {
+        // Media controls
         Row(
             modifier = Modifier.fillMaxWidth(),
             horizontalArrangement = Arrangement.Center,
@@ -362,7 +361,7 @@ private fun ActionButton(
     label: String,
     onClick: () -> Unit,
 ) {
-    AppColumn(
+    Column(
         horizontalAlignment = Alignment.CenterHorizontally,
     ) {
         MediumTonalButton(

+ 5 - 16
app/src/main/java/io/legado/app/ui/book/read/sheet/ReadStyleSheet.kt

@@ -30,7 +30,6 @@ import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookButtonConfigItem
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.book.read.ReadBookStyleConfig
-import io.legado.app.ui.widget.components.AppColumn
 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
@@ -73,9 +72,9 @@ fun ReadStyleContent(
         }
     }
 
-    AppColumn(
-        modifier
-            .fillMaxWidth()
+    Column(
+        modifier = modifier
+            .fillMaxWidth(),
     ) {
         HorizontalPager(
             state = pagerState,
@@ -101,13 +100,7 @@ fun ReadStyleContent(
                         onOpenTextTitle = onOpenTextTitle,
                         onOpenPaddingConfig = onOpenPaddingConfig,
                         onShareLayoutChange = { shareLayout ->
-                            onIntent(
-                                ReadBookIntent.UpdateConfig(
-                                    ConfigUpdate.ShareLayout(
-                                        shareLayout
-                                    )
-                                )
-                            )
+                            onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShareLayout(shareLayout)))
                         },
                         onStyleSelect = { index ->
                             onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.StyleSelect(index)))
@@ -142,14 +135,10 @@ fun ReadStyleContent(
                         scope.launch {
                             pagerState.animateScrollToPage(
                                 page = index,
-                                animationSpec = tween(
-                                    durationMillis = 300,
-                                    easing = FastOutSlowInEasing
-                                )
+                                animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing)
                             )
                         }
                     }
-
                     2 -> onOpenHeaderFooterConfig()
                     3 -> onOpenMoreConfig()
                 }

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

@@ -92,7 +92,6 @@ import io.legado.app.ui.book.toc.rule.TxtTocRuleActivity
 import io.legado.app.ui.replace.ReplaceEditRoute
 import io.legado.app.ui.replace.ReplaceRuleActivity
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButtonMenu
 import io.legado.app.ui.widget.components.EmptyMessage
 import io.legado.app.ui.widget.components.FabMenuItem
@@ -350,8 +349,8 @@ private fun ReaderBookHeader(book: Book?) {
             sourceOrigin = book?.origin,
             modifier = Modifier.width(40.dp),
         )
-        AppColumn(
-            Modifier.weight(1f)
+        Column(
+            modifier = Modifier.weight(1f),
         ) {
             AppText(
                 text = book?.name.orEmpty(),
@@ -378,6 +377,7 @@ private fun ReaderBookHeader(book: Book?) {
                     text = if (total > 0) "$current / $total" else "--",
                 )
             }
+
         }
     }
 }
@@ -414,7 +414,7 @@ private fun InformationRow(label: String, value: String) {
         containerColor = LegadoTheme.colorScheme.surfaceContainerLow,
         modifier = Modifier.fillMaxWidth(),
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(horizontal = 12.dp, vertical = 10.dp),
             verticalArrangement = Arrangement.spacedBy(3.dp),
         ) {
@@ -581,9 +581,7 @@ private fun ReaderBookTocPage(
         }
     }
 
-    AppColumn(
-        Modifier.fillMaxSize()
-    ) {
+    Column(modifier = Modifier.fillMaxSize()) {
         Row(
             modifier = Modifier
                 .fillMaxWidth()
@@ -776,9 +774,7 @@ private fun ReaderSheetChapterItem(
             modifier = Modifier.padding(start = 12.dp, end = 4.dp, top = 8.dp, bottom = 8.dp),
             verticalAlignment = Alignment.CenterVertically,
         ) {
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
                 AppText(
                     modifier = Modifier.padding(vertical = 8.dp),
                     text = item.title,
@@ -964,9 +960,7 @@ private fun ReaderBookBookmarksPage(
 ) {
     var menuExpanded by rememberSaveable { mutableStateOf(false) }
     val date = remember { SimpleDateFormat("yyyyMMdd_HHmm", Locale.getDefault()).format(Date()) }
-    AppColumn(
-        Modifier.fillMaxSize()
-    ) {
+    Column(modifier = Modifier.fillMaxSize()) {
         Row(
             modifier = Modifier
                 .fillMaxWidth()
@@ -1095,7 +1089,7 @@ private fun ReaderSheetBookmarkItem(
         contentColor = contentColor,
         modifier = modifier.fillMaxWidth(),
     ) {
-        AppColumn(
+        Column(
             modifier = Modifier.padding(horizontal = 12.dp, vertical = 10.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {

+ 3 - 4
app/src/main/java/io/legado/app/ui/book/read/sheet/ShadowSetSheet.kt

@@ -19,7 +19,6 @@ import io.legado.app.R
 import io.legado.app.ui.book.read.ReadSheetConfigUiState
 import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.TinyColorSettingItem
@@ -45,11 +44,11 @@ fun ShadowSetSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.text_shadow_set),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .verticalScroll(rememberScrollState())
-                .padding(bottom = 16.dp)
+                .padding(bottom = 16.dp),
         ) {
             TinySwitchSettingItem(
                 title = stringResource(R.string.text_shadow_set),

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/read/sheet/SimulatedReadingSheet.kt

@@ -28,7 +28,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.model.ReadBook
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.settingItem.TinySwitchSettingItem
 import java.time.Instant
 import java.time.LocalDate
@@ -54,8 +53,7 @@ fun SimulatedReadingSheet(
         containerColor = LegadoTheme.colorScheme.surfaceContainer,
         title = { Text(stringResource(R.string.simulated_reading)) },
         text = {
-            AppColumn(
-            ) {
+            Column {
                 OutlinedTextField(
                     value = startDate.format(dateFormatter),
                     onValueChange = {},
@@ -74,6 +72,7 @@ fun SimulatedReadingSheet(
                     onCheckedChange = { enabled = it },
                 )
                 Spacer(modifier = Modifier.height(12.dp))
+                // Start chapter + daily chapters
                 Row(modifier = Modifier.fillMaxWidth()) {
                     OutlinedTextField(
                         value = startChapter,

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

@@ -64,7 +64,6 @@ import io.legado.app.ui.book.read.ReadBookButtonConfigItem
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.book.read.ReadBookSheet
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.SectionTitle
 import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
 import io.legado.app.ui.widget.components.pager.pagerHeight
@@ -130,8 +129,8 @@ internal fun SystemMenuPage(
         }
     }
 
-    AppColumn(
-        modifier.fillMaxWidth()
+    Column(
+        modifier = modifier.fillMaxWidth(),
     ) {
         val tabTitles = listOf(
             stringResource(R.string.read_config_menu_system),
@@ -148,10 +147,7 @@ internal fun SystemMenuPage(
                     try {
                         pagerState.animateScrollToPage(
                             page = index,
-                            animationSpec = tween(
-                                durationMillis = 300,
-                                easing = FastOutSlowInEasing
-                            )
+                            animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing)
                         )
                     } finally {
                         clickScrollCount = (clickScrollCount - 1).coerceAtLeast(0)
@@ -214,86 +210,17 @@ internal fun SystemMenuPage(
         onColorSelected = { color ->
             when (colorPickerId) {
                 COLOR_BG -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBgColor(color)))
-                COLOR_MENU_ACCENT -> onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.MenuAccentColor(
-                            color
-                        )
-                    )
-                )
-
-                COLOR_MENU_CONTAINER -> onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.MenuContainerColor(
-                            color
-                        )
-                    )
-                )
-
-                COLOR_BG_NIGHT -> onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.MenuBgColorNight(
-                            color
-                        )
-                    )
-                )
-
-                COLOR_MENU_ACCENT_NIGHT -> onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.MenuAccentColorNight(
-                            color
-                        )
-                    )
-                )
-
-                COLOR_MENU_CONTAINER_NIGHT -> onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.MenuContainerColorNight(
-                            color
-                        )
-                    )
-                )
-
+                COLOR_MENU_ACCENT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuAccentColor(color)))
+                COLOR_MENU_CONTAINER -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuContainerColor(color)))
+                COLOR_BG_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBgColorNight(color)))
+                COLOR_MENU_ACCENT_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuAccentColorNight(color)))
+                COLOR_MENU_CONTAINER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuContainerColorNight(color)))
                 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
-                        )
-                    )
-                )
-
-                COLOR_MENU_TEXT -> onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.MenuTextColor(
-                            color
-                        )
-                    )
-                )
-
-                COLOR_MENU_TEXT_NIGHT -> onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.MenuTextColorNight(
-                            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)))
+                COLOR_MENU_TEXT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuTextColor(color)))
+                COLOR_MENU_TEXT_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuTextColorNight(color)))
             }
             showColorPicker = false
         },
@@ -340,11 +267,11 @@ private fun GlobalMenuTab(
         .takeIf { it != 0 }
         ?: nightMenuBgColor
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp)
-            .verticalScroll(rememberScrollState())
+            .verticalScroll(rememberScrollState()),
     ) {
         TinyDropdownSettingItem(
             title = stringResource(R.string.tool_bar_style),
@@ -433,10 +360,7 @@ private fun GlobalMenuTab(
                             enabled = true,
                             onClickColor = { isNight ->
                                 if (isNight) {
-                                    onShowColorPicker(
-                                        COLOR_MENU_CONTAINER_NIGHT,
-                                        nightMenuContainerColor
-                                    )
+                                    onShowColorPicker(COLOR_MENU_CONTAINER_NIGHT, nightMenuContainerColor)
                                 } else {
                                     onShowColorPicker(COLOR_MENU_CONTAINER, dayMenuContainerColor)
                                 }
@@ -516,10 +440,7 @@ private fun GlobalMenuTab(
                     },
                     onClickColor = { isNight ->
                         if (isNight) {
-                            onShowColorPicker(
-                                COLOR_BORDER_NIGHT,
-                                preferences.readMenuBorderColorNight
-                            )
+                            onShowColorPicker(COLOR_BORDER_NIGHT, preferences.readMenuBorderColorNight)
                         } else {
                             onShowColorPicker(COLOR_BORDER, preferences.readMenuBorderColor)
                         }
@@ -580,6 +501,8 @@ private fun GlobalMenuTab(
                 }
             },
         )
+
+        // --- Floating icon settings (at bottom) ---
         SectionTitle(stringResource(R.string.show_title_bar_icons))
 
         TinySwitchSettingItem(
@@ -658,11 +581,11 @@ private fun BottomBarTab(
         preferences.readMenuBottomBarBlurMode
     }
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp)
-            .verticalScroll(rememberScrollState())
+            .verticalScroll(rememberScrollState()),
     ) {
         val readSliderModeEntries = stringArrayResource(R.array.read_slider_mode)
         val readSliderModeValues = stringArrayResource(R.array.read_slider_mode_value)
@@ -836,11 +759,11 @@ private fun TopBarTab(
     val titleBarModeEntries = stringArrayResource(R.array.title_bar_mode)
     val titleBarModeValues = stringArrayResource(R.array.title_bar_mode_value)
 
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp)
-            .verticalScroll(rememberScrollState())
+            .verticalScroll(rememberScrollState()),
     ) {
         TinySwitchSettingItem(
             title = stringResource(R.string.read_menu_top_bar_title_capsule),

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

@@ -46,7 +46,6 @@ 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.AppColumn
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
@@ -136,11 +135,11 @@ fun TextSelectMenuConfigSheet(
             )
         }
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .fillMaxHeight(0.8f)
-                .padding(bottom = 16.dp)
+                .padding(bottom = 16.dp),
         ) {
             LazyColumn(
                 state = lazyListState,
@@ -219,8 +218,7 @@ fun TextSelectMenuConfigSheet(
 
 
                 stickyHeader(key = "group2") {
-                    val subtitle =
-                        if (expandTextMenu) stringResource(R.string.merged_in_multiline) else null
+                    val subtitle = if (expandTextMenu) stringResource(R.string.merged_in_multiline) else null
                     SheetHeader(
                         isCollapsed = !group2Expanded,
                         onToggle = { group2Expanded = !group2Expanded },
@@ -271,7 +269,7 @@ fun TextSelectMenuConfigSheet(
                 }
 
 
-                item(key = "group_3") {
+                item (key="group_3"){
                     Box(
                         modifier = Modifier
                             .fillMaxWidth()
@@ -288,8 +286,7 @@ fun TextSelectMenuConfigSheet(
                                 if (expanded) {
                                     coroutineScope.launch {
                                         delay(300.milliseconds)
-                                        val targetIndex =
-                                            lazyListState.layoutInfo.totalItemsCount - 1
+                                        val targetIndex = lazyListState.layoutInfo.totalItemsCount - 1
                                         if (targetIndex >= 0) {
                                             lazyListState.animateScrollToItem(targetIndex)
                                         }
@@ -306,8 +303,7 @@ fun TextSelectMenuConfigSheet(
                                         }
                                         coroutineScope.launch {
                                             delay(200.milliseconds)
-                                            val targetIndex =
-                                                lazyListState.layoutInfo.totalItemsCount - 1
+                                            val targetIndex = lazyListState.layoutInfo.totalItemsCount - 1
                                             if (targetIndex >= 0) {
                                                 lazyListState.scrollToItem(targetIndex)
                                             }

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

@@ -49,7 +49,6 @@ import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
 import io.legado.app.ui.book.read.ReadSheetConfigUiState
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppSlider
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.SectionTitle
@@ -156,8 +155,8 @@ internal fun ReadStyleTextTitleContent(
         orientation = Orientation.Horizontal,
     )
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
     ) {
         CardTabRow(
@@ -219,11 +218,11 @@ internal fun LayoutSpacingPage(
     var paragraphSpacing by remember { mutableFloatStateOf(config.paragraphSpacing.toFloat()) }
     var indentCount by remember { mutableIntStateOf(config.paragraphIndentCount) }
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp)
-            .verticalScroll(rememberScrollState())
+            .verticalScroll(rememberScrollState()),
     ) {
         SectionTitle(stringResource(R.string.read_config_body_spacing))
         TinySliderSettingItem(
@@ -233,15 +232,7 @@ internal fun LayoutSpacingPage(
             steps = 3,
             onValueChange = { value ->
                 indentCount = value.toInt()
-                onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.ParagraphIndent(
-                            " ".repeat(
-                                indentCount
-                            )
-                        )
-                    )
-                )
+                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ParagraphIndent(" ".repeat(indentCount))))
             },
         )
         TinySliderSettingItem(
@@ -299,11 +290,11 @@ internal fun TextEffectsPage(
     var colorPickerId by remember { mutableIntStateOf(0) }
     var colorPickerInitial by remember { mutableIntStateOf(0) }
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp)
-            .verticalScroll(rememberScrollState())
+            .verticalScroll(rememberScrollState()),
     ) {
         SectionTitle(stringResource(R.string.text_typeface))
         TinySwitchSettingItem(
@@ -340,6 +331,8 @@ internal fun TextEffectsPage(
                 onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ChineseConverterType(it.toInt())))
             },
         )
+
+        // Colors
         SectionTitle(stringResource(R.string.read_color))
         TinyColorSettingItem(
             title = stringResource(R.string.text_color),
@@ -428,11 +421,11 @@ internal fun TitleSettingsPage(
     var colorPickerId by remember { mutableIntStateOf(0) }
     var colorPickerInitial by remember { mutableIntStateOf(0) }
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp)
-            .verticalScroll(rememberScrollState())
+            .verticalScroll(rememberScrollState()),
     ) {
         TinyDropdownSettingItem(
             title = stringResource(R.string.body_title),
@@ -488,11 +481,15 @@ internal fun TitleSettingsPage(
                 showColorPicker = true
             },
         )
+
+        // Title font
         TinyClickableSettingItem(
             title = stringResource(R.string.read_config_title_settings),
             imageVector = Icons.Default.TextFields,
             onClick = onOpenTitleFontSelect,
         )
+
+        // Title segmentation
         TinyDropdownSettingItem(
             title = stringResource(R.string.split_title_mode),
             selectedValue = titleSegType.toString(),
@@ -516,13 +513,7 @@ internal fun TitleSettingsPage(
                 steps = 18,
                 onValueChange = { value ->
                     titleSegDistance = value.toInt()
-                    onIntent(
-                        ReadBookIntent.UpdateConfig(
-                            ConfigUpdate.TitleSegDistance(
-                                titleSegDistance
-                            )
-                        )
-                    )
+                    onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleSegDistance(titleSegDistance)))
                 },
             )
         }
@@ -558,6 +549,8 @@ internal fun TitleSettingsPage(
                 onDismiss = { showFlagDialog = false },
             )
         }
+
+        // Title spacing sliders
         TinySliderSettingItem(
             title = stringResource(R.string.subtitle_scale),
             value = titleSegScaling,
@@ -576,13 +569,7 @@ internal fun TitleSettingsPage(
             valueRange = 0f..20f,
             onValueChange = { value ->
                 titleLineSpacingExtra = value.toInt()
-                onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.TitleLineSpacingExtra(
-                            titleLineSpacingExtra
-                        )
-                    )
-                )
+                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleLineSpacingExtra(titleLineSpacingExtra)))
             },
         )
         TinySliderSettingItem(
@@ -591,13 +578,7 @@ internal fun TitleSettingsPage(
             valueRange = -30f..30f,
             onValueChange = { value ->
                 titleLineSpacingSub = value.toInt()
-                onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.TitleLineSpacingSub(
-                            titleLineSpacingSub
-                        )
-                    )
-                )
+                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleLineSpacingSub(titleLineSpacingSub)))
             },
         )
         TinySliderSettingItem(
@@ -624,15 +605,10 @@ internal fun TitleSettingsPage(
             valueRange = 0f..200f,
             onValueChange = { value ->
                 titleBottomSpacing = value.toInt()
-                onIntent(
-                    ReadBookIntent.UpdateConfig(
-                        ConfigUpdate.TitleBottomSpacing(
-                            titleBottomSpacing
-                        )
-                    )
-                )
+                onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleBottomSpacing(titleBottomSpacing)))
             },
         )
+
     }
 
     // Color picker
@@ -645,7 +621,6 @@ internal fun TitleSettingsPage(
                 COLOR_TITLE -> {
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleColor(color)))
                 }
-
                 COLOR_TITLE_NIGHT -> {
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleColorNight(color)))
                 }
@@ -673,8 +648,7 @@ private fun FontWeightSetting(
     }
     val weightEntries = stringArrayResource(R.array.text_font_weight)
 
-    AppColumn(
-    ) {
+    Column {
         Row(
             modifier = Modifier.fillMaxWidth(),
             horizontalArrangement = Arrangement.spacedBy(8.dp),

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

@@ -24,7 +24,6 @@ import io.legado.app.R
 import io.legado.app.ui.book.read.ReadSheetConfigUiState
 import io.legado.app.ui.book.read.ConfigUpdate
 import io.legado.app.ui.book.read.ReadBookIntent
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.TinyColorSettingItem
@@ -53,11 +52,11 @@ fun UnderlineConfigSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.text_underline),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .verticalScroll(rememberScrollState())
-                .padding(bottom = 16.dp)
+                .padding(bottom = 16.dp),
         ) {
             TinySwitchSettingItem(
                 title = stringResource(R.string.text_underline),
@@ -93,6 +92,8 @@ fun UnderlineConfigSheet(
                     onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.UnderlineExtend(it)))
                 },
             )
+
+            // Underline height & padding
             TinySliderSettingItem(
                 title = stringResource(R.string.underline_height),
                 value = underlineHeight,
@@ -113,6 +114,8 @@ fun UnderlineConfigSheet(
             )
 
             Spacer(Modifier.height(8.dp))
+
+            // Dotted line section title
             Text(
                 text = stringResource(R.string.text_dottedline),
                 style = MaterialTheme.typography.titleSmallEmphasized,
@@ -123,6 +126,8 @@ fun UnderlineConfigSheet(
             )
 
             Spacer(Modifier.height(8.dp))
+
+            // Dotted line sliders
             TinySliderSettingItem(
                 title = stringResource(R.string.dotted_line_black),
                 value = dottedBase,

+ 16 - 46
app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordOverviewScreen.kt

@@ -59,7 +59,6 @@ import io.legado.app.ui.book.readRecord.component.StatItem
 import io.legado.app.ui.book.readRecord.component.StatsGridCard
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.button.series.MediumPlainButton
 import io.legado.app.ui.widget.components.card.GlassCard
@@ -115,8 +114,8 @@ fun ReadRecordOverviewScreen(
             )
         }
     ) { padding ->
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxSize()
                 .padding(padding)
         ) {
@@ -151,12 +150,10 @@ fun ReadRecordOverviewScreen(
                             readingTime.hours,
                             readingTime.minutes,
                         )
-
                         readingTime.hours > 0 -> stringResource(
                             R.string.whole_hours_format,
                             readingTime.hours,
                         )
-
                         else -> stringResource(
                             R.string.minutes_format,
                             readingTime.minutes,
@@ -167,26 +164,11 @@ fun ReadRecordOverviewScreen(
                             stringResource(R.string.reading_time),
                             readingTimeText,
                         ),
-                        StatItem(
-                            stringResource(R.string.reading_days),
-                            stringResource(R.string.days_format, state.readingDays)
-                        ),
-                        StatItem(
-                            stringResource(R.string.total_read_books),
-                            stringResource(R.string.books_format, state.totalBooks)
-                        ),
-                        StatItem(
-                            stringResource(R.string.finished_books),
-                            stringResource(R.string.books_format, state.finishedBooks)
-                        ),
-                        StatItem(
-                            stringResource(R.string.reading_books),
-                            stringResource(R.string.books_format, state.readingBooks)
-                        ),
-                        StatItem(
-                            stringResource(R.string.reading_words),
-                            ReadRecordFormatter.formatWords(state.totalWords)
-                        )
+                        StatItem(stringResource(R.string.reading_days), stringResource(R.string.days_format, state.readingDays)),
+                        StatItem(stringResource(R.string.total_read_books), stringResource(R.string.books_format, state.totalBooks)),
+                        StatItem(stringResource(R.string.finished_books), stringResource(R.string.books_format, state.finishedBooks)),
+                        StatItem(stringResource(R.string.reading_books), stringResource(R.string.books_format, state.readingBooks)),
+                        StatItem(stringResource(R.string.reading_words), ReadRecordFormatter.formatWords(state.totalWords))
                     )
                     StatsGridCard(title = stringResource(R.string.reading_data), items = stats)
                 }
@@ -301,9 +283,7 @@ fun HeatmapCard(state: ReadRecordOverviewUiState) {
             .fillMaxWidth()
             .adaptiveHorizontalPadding(vertical = 8.dp)
     ) {
-        AppColumn(
-            Modifier.padding(16.dp)
-        ) {
+        Column(modifier = Modifier.padding(16.dp)) {
             Row(verticalAlignment = Alignment.CenterVertically) {
                 Icon(
                     imageVector = Icons.Default.GridOn,
@@ -312,10 +292,7 @@ fun HeatmapCard(state: ReadRecordOverviewUiState) {
                     modifier = Modifier.size(20.dp)
                 )
                 Spacer(modifier = Modifier.width(8.dp))
-                AppText(
-                    stringResource(R.string.reading_heatmap),
-                    style = LegadoTheme.typography.titleMedium
-                )
+                AppText(stringResource(R.string.reading_heatmap), style = LegadoTheme.typography.titleMedium)
             }
             Spacer(modifier = Modifier.height(8.dp))
             HeatmapCalendarSection(
@@ -340,9 +317,7 @@ fun TopReadingListCard(
             .fillMaxWidth()
             .adaptiveHorizontalPadding(vertical = 8.dp)
     ) {
-        AppColumn(
-            Modifier.padding(vertical = 16.dp)
-        ) {
+        Column(modifier = Modifier.padding(vertical = 16.dp)) {
             Row(
                 modifier = Modifier.padding(horizontal = 16.dp),
                 verticalAlignment = Alignment.CenterVertically
@@ -360,7 +335,7 @@ fun TopReadingListCard(
                 )
             }
             Spacer(modifier = Modifier.height(8.dp))
-
+            
             topBooks.forEachIndexed { index, book ->
                 var coverPath by remember { mutableStateOf<String?>(null) }
                 LaunchedEffect(book.bookName, book.bookAuthor) {
@@ -440,9 +415,7 @@ fun ReadingCalendarCard(
             .fillMaxWidth()
             .adaptiveHorizontalPadding(vertical = 8.dp)
     ) {
-        AppColumn(
-            Modifier.padding(16.dp)
-        ) {
+        Column(modifier = Modifier.padding(16.dp)) {
             Row(verticalAlignment = Alignment.CenterVertically) {
                 Icon(
                     imageVector = Icons.Default.CalendarMonth,
@@ -451,13 +424,10 @@ fun ReadingCalendarCard(
                     modifier = Modifier.size(20.dp)
                 )
                 Spacer(modifier = Modifier.width(8.dp))
-                AppText(
-                    stringResource(R.string.reading_calendar),
-                    style = LegadoTheme.typography.titleMedium
-                )
+                AppText(stringResource(R.string.reading_calendar), style = LegadoTheme.typography.titleMedium)
             }
             Spacer(modifier = Modifier.height(16.dp))
-
+            
             Row(modifier = Modifier.fillMaxWidth()) {
                 val days = listOf("日", "一", "二", "三", "四", "五", "六")
                 days.forEach { day ->
@@ -469,7 +439,7 @@ fun ReadingCalendarCard(
                     )
                 }
             }
-
+            
             Spacer(modifier = Modifier.height(8.dp))
 
             val totalCells = ((daysInMonth + firstDayOfWeek + 6) / 7) * 7
@@ -478,7 +448,7 @@ fun ReadingCalendarCard(
                     for (j in 0 until 7) {
                         val cellIndex = i + j
                         val dayOfMonth = cellIndex - firstDayOfWeek + 1
-
+                        
                         Box(
                             modifier = Modifier
                                 .weight(1f)

+ 20 - 39
app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt

@@ -76,7 +76,6 @@ import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.theme.fadingEdge
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.CollapsibleHeader
 import io.legado.app.ui.widget.components.EmptyMessage
@@ -228,8 +227,7 @@ fun ReadRecordScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         snackbarHost = { SnackbarHost(snackbarHostState) },
         topBar = {
-            AppColumn(
-            ) {
+            Column {
                 GlassMediumFlexibleTopAppBar(
                     title = if (inSelectionMode) {
                         stringResource(R.string.selected_count, selectedItemKeys.size)
@@ -299,10 +297,7 @@ fun ReadRecordScreen(
                                 AppIcon(icon, description)
                             }
                             AppIconButton(onClick = { showSearch = !showSearch }) {
-                                AppIcon(
-                                    Icons.Default.Search,
-                                    contentDescription = stringResource(R.string.search)
-                                )
+                                AppIcon(Icons.Default.Search, contentDescription = stringResource(R.string.search))
                             }
                             AppIconButton(onClick = { showActionsSheet = true }) {
                                 AppIcon(
@@ -471,16 +466,12 @@ fun ReadRecordScreen(
         onDismissRequest = { pendingDeleteAction = null },
         title = stringResource(R.string.confirm_delete_read_record),
         content = { _ ->
-            AppColumn(
-            ) {
+            Column {
                 AppText(
                     if (pendingDeleteCount == -1) {
                         stringResource(R.string.clear_read_records_message)
                     } else if (pendingDeleteCount > 1) {
-                        stringResource(
-                            R.string.delete_selected_read_records_message,
-                            pendingDeleteCount
-                        )
+                        stringResource(R.string.delete_selected_read_records_message, pendingDeleteCount)
                     } else {
                         stringResource(R.string.delete_read_record_message)
                     }
@@ -557,8 +548,7 @@ fun ReadRecordScreen(
         title = stringResource(R.string.merge_read_records),
         content = { (targetRecord, candidates) ->
             val unknownAuthor = stringResource(R.string.unknown_author)
-            AppColumn(
-            ) {
+            Column {
                 AppText(
                     stringResource(
                         R.string.merge_read_records_message,
@@ -624,8 +614,8 @@ private fun ReadRecordActionsSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.read_record_options)
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 16.dp),
             verticalArrangement = Arrangement.spacedBy(8.dp)
@@ -781,8 +771,8 @@ fun HeatmapCalendarSection(
         }
     }
 
-    AppColumn(
-        modifier
+    Column(
+        modifier = modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp, vertical = 8.dp)
             .padding(bottom = 32.dp)
@@ -1060,9 +1050,7 @@ fun LatestReadItem(
 
         Spacer(modifier = Modifier.width(if (inSelectionMode) 8.dp else 16.dp))
 
-        AppColumn(
-            Modifier.weight(1f)
-        ) {
+        Column(modifier = Modifier.weight(1f)) {
             AppText(
                 text = record.bookName,
                 style = LegadoTheme.typography.titleMedium,
@@ -1182,7 +1170,7 @@ fun TimelineSessionItem(
                 .padding(start = contentPaddingStart, end = 16.dp, top = 8.dp, bottom = 8.dp),
             verticalAlignment = Alignment.CenterVertically
         ) {
-            AppColumn(
+            Column(
                 modifier = Modifier.width(48.dp),
                 verticalArrangement = Arrangement.Center
             ) {
@@ -1203,8 +1191,7 @@ fun TimelineSessionItem(
                 )
                 SelectionCheckmark(inSelectionMode, isSelected)
                 Spacer(modifier = Modifier.width(8.dp))
-                AppColumn(
-                ) {
+                Column {
                     AppText(
                         text = session.bookName,
                         style = LegadoTheme.typography.titleMedium,
@@ -1282,9 +1269,7 @@ fun ReadRecordItem(
 
         Spacer(modifier = Modifier.width(if (inSelectionMode) 8.dp else 16.dp))
 
-        AppColumn(
-            Modifier.weight(1f)
-        ) {
+        Column(modifier = Modifier.weight(1f)) {
             AppText(
                 text = detail.bookName,
                 style = LegadoTheme.typography.titleMedium,
@@ -1297,10 +1282,7 @@ fun ReadRecordItem(
             )
             Spacer(modifier = Modifier.height(8.dp))
             AppText(
-                text = stringResource(
-                    R.string.reading_time_with_value,
-                    formatDuring(detail.readTime)
-                ),
+                text = stringResource(R.string.reading_time_with_value, formatDuring(detail.readTime)),
                 color = MaterialTheme.colorScheme.outline,
                 style = LegadoTheme.typography.labelSmall
             )
@@ -1381,9 +1363,8 @@ fun ReadingSummaryCard(
             verticalAlignment = Alignment.CenterVertically
         ) {
 
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
+
                 AppText(
                     text = title,
                     style = LegadoTheme.typography.labelLarge,
@@ -1393,8 +1374,8 @@ fun ReadingSummaryCard(
                 Spacer(modifier = Modifier.height(4.dp))
 
                 Row(verticalAlignment = Alignment.Bottom) {
-                    AppText(
-                        text = stringResource(R.string.read_books_prefix),
+                AppText(
+                    text = stringResource(R.string.read_books_prefix),
                         style = LegadoTheme.typography.titleMedium
                     )
                     AppText(
@@ -1403,8 +1384,8 @@ fun ReadingSummaryCard(
                         color = LegadoTheme.colorScheme.primary,
                         fontWeight = FontWeight.Bold,
                     )
-                    AppText(
-                        text = stringResource(R.string.read_books_suffix),
+                AppText(
+                    text = stringResource(R.string.read_books_suffix),
                         style = LegadoTheme.typography.titleMedium
                     )
                 }

+ 2 - 9
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordCharts.kt

@@ -32,7 +32,6 @@ import io.legado.app.ui.book.readRecord.ReadPeriod
 import io.legado.app.ui.book.readRecord.ReadRecordFormatter
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.text.AppText
 import java.time.LocalDate
@@ -59,9 +58,7 @@ fun ReadingTimeBarChartCard(
             .fillMaxWidth()
             .adaptiveHorizontalPadding(vertical = 8.dp)
     ) {
-        AppColumn(
-            Modifier.padding(16.dp)
-        ) {
+        Column(modifier = Modifier.padding(16.dp)) {
             Row(verticalAlignment = Alignment.CenterVertically) {
                 Icon(
                     imageVector = Icons.Default.BarChart,
@@ -133,7 +130,6 @@ fun ReadingTimeBarChartCard(
                             ReadPeriod.WEEK -> when (date.dayOfWeek.value) {
                                 1 -> "一"; 2 -> "二"; 3 -> "三"; 4 -> "四"; 5 -> "五"; 6 -> "六"; 7 -> "日"; else -> ""
                             }
-
                             else -> date.dayOfMonth.toString()
                         }
 
@@ -163,10 +159,7 @@ fun ReadingTimeBarChartCard(
                                 )
                             }
 
-                            Box(
-                                modifier = Modifier.height(20.dp),
-                                contentAlignment = Alignment.TopCenter
-                            ) {
+                            Box(modifier = Modifier.height(20.dp), contentAlignment = Alignment.TopCenter) {
                                 if (showLabel) {
                                     AppText(
                                         text = labelText,

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordHeatmap.kt

@@ -8,7 +8,6 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.heatmap.*
 import io.legado.app.ui.widget.components.text.AppText
 import java.time.LocalDate
@@ -27,7 +26,7 @@ fun HeatmapCalendarSection(
     val days = rememberDaysInRange(startDate, endDate)
     val weeks = rememberWeeks(days, startDate)
 
-    AppColumn(
+    Column(
         modifier = modifier.fillMaxWidth(),
         horizontalAlignment = Alignment.Start
     ) {

+ 3 - 10
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordListItems.kt

@@ -28,7 +28,6 @@ import io.legado.app.ui.book.readRecord.ReadRecordFormatter
 import io.legado.app.ui.book.readRecord.ReadRecordViewModel
 import io.legado.app.ui.book.readRecord.TimelineItem
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.image.cover.CoilBookCover
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.StringUtils.formatFriendlyDate
@@ -59,9 +58,7 @@ fun LatestReadItem(
             modifier = Modifier.size(48.dp, 64.dp)
         )
         Spacer(modifier = Modifier.width(16.dp))
-        AppColumn(
-            Modifier.weight(1f)
-        ) {
+        Column(modifier = Modifier.weight(1f)) {
             AppText(
                 text = record.bookName,
                 style = LegadoTheme.typography.titleMedium,
@@ -116,9 +113,7 @@ fun TimelineSessionItem(
             modifier = Modifier.size(40.dp, 56.dp)
         )
         Spacer(modifier = Modifier.width(12.dp))
-        AppColumn(
-            Modifier.weight(1f)
-        ) {
+        Column(modifier = Modifier.weight(1f)) {
             AppText(
                 text = session.bookName,
                 style = LegadoTheme.typography.bodyMedium,
@@ -165,9 +160,7 @@ fun ReadRecordItem(
             modifier = Modifier.size(40.dp, 56.dp)
         )
         Spacer(modifier = Modifier.width(16.dp))
-        AppColumn(
-            Modifier.weight(1f)
-        ) {
+        Column(modifier = Modifier.weight(1f)) {
             AppText(
                 text = detail.bookName,
                 style = LegadoTheme.typography.bodyLarge,

+ 2 - 5
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordStats.kt

@@ -25,7 +25,6 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.icon.AppIcon
 import io.legado.app.ui.widget.components.text.AppText
@@ -43,9 +42,7 @@ fun StatsGridCard(
             .fillMaxWidth()
             .adaptiveHorizontalPadding(vertical = 8.dp)
     ) {
-        AppColumn(
-            Modifier.padding(16.dp)
-        ) {
+        Column(modifier = Modifier.padding(16.dp)) {
             Row(verticalAlignment = Alignment.CenterVertically) {
                 AppIcon(
                     imageVector = Icons.Default.Equalizer,
@@ -83,7 +80,7 @@ private fun StatCell(
     item: StatItem,
     modifier: Modifier = Modifier
 ) {
-    AppColumn(
+    Column(
         modifier = modifier,
         horizontalAlignment = Alignment.Start
     ) {

+ 3 - 10
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordSummary.kt

@@ -22,7 +22,6 @@ import io.legado.app.ui.book.readRecord.ReadRecordUiState
 import io.legado.app.ui.book.readRecord.ReadRecordViewModel
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.image.cover.CoilBookCover
 import io.legado.app.ui.widget.components.text.AppText
@@ -89,22 +88,16 @@ fun ReadingSummaryCard(
             modifier = Modifier.padding(16.dp),
             verticalAlignment = Alignment.CenterVertically
         ) {
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
                 AppText(title, style = LegadoTheme.typography.titleMedium)
                 Spacer(modifier = Modifier.height(4.dp))
                 AppText(
-                    text = "共阅读 $bookCount 本书,时长 ${
-                        ReadRecordFormatter.formatDuration(
-                            totalTimeMillis
-                        )
-                    }",
+                    text = "共阅读 $bookCount 本书,时长 ${ReadRecordFormatter.formatDuration(totalTimeMillis)}",
                     style = LegadoTheme.typography.bodyMedium,
                     color = LegadoTheme.colorScheme.onSurfaceVariant
                 )
             }
-
+            
             BookStackView(
                 bookNamesForCover = bookNamesForCover,
                 viewModel = viewModel

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/readaloud/casting/BookVoiceCastingScreen.kt

@@ -37,7 +37,6 @@ import io.legado.app.R
 import io.legado.app.domain.model.readaloud.ReadAloudVoice
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.icon.AppIcon
@@ -236,7 +235,7 @@ private fun VoiceCastingCard(
                 }
             },
             supportingContent = {
-                AppColumn(verticalArrangement = Arrangement.spacedBy(2.dp)) {
+                Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
                     if (item.description.isNotBlank()) {
                         AnimatedTextLine(
                             text = item.description,
@@ -282,7 +281,7 @@ private fun VoicePickerSheet(
         title = picker?.let { subjectTitle(it.kind, it.name) }.orEmpty(),
     ) {
         if (picker == null) return@AppModalBottomSheet
-        AppColumn(
+        Column(
             modifier = Modifier
                 .fillMaxWidth(),
             verticalArrangement = Arrangement.spacedBy(8.dp),

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/readaloud/cloudtts/CloudTtsScreen.kt

@@ -49,7 +49,6 @@ import io.legado.app.domain.model.readaloud.ReadAloudVoice
 import io.legado.app.domain.model.readaloud.profile
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
@@ -690,7 +689,7 @@ private fun CloudTtsEngineEditorContent(
     val profile = provider.profile
     LazyColumn {
         item {
-            AppColumn(
+            Column(
                 verticalArrangement = Arrangement.spacedBy(4.dp)
             ) {
                 MenuButton(profile.displayName) { providerMenu = true }

+ 7 - 20
app/src/main/java/io/legado/app/ui/book/readaloud/player/ReadAloudPlayerScreen.kt

@@ -95,7 +95,6 @@ import io.legado.app.constant.ReadAloudBgMode
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.hazeStyle.HazeLegado
 import io.legado.app.ui.util.rememberBlurBackdrop
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.button.series.MediumPlainButton
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
@@ -189,7 +188,7 @@ fun ReadAloudPlayerScreenContent(
                         .padding(horizontal = 24.dp, vertical = 16.dp),
                     verticalAlignment = Alignment.CenterVertically,
                 ) {
-                    AppColumn(
+                    Column(
                         modifier = Modifier.weight(1f),
                         horizontalAlignment = Alignment.Start,
                     ) {
@@ -237,8 +236,8 @@ fun ReadAloudPlayerScreenContent(
                 } else {
                     Modifier
                 }
-                AppColumn(
-                    Modifier
+                Column(
+                    modifier = Modifier
                         .fillMaxWidth()
                         .clip(RectangleShape)
                         .then(hazeModifier)
@@ -260,20 +259,8 @@ fun ReadAloudPlayerScreenContent(
                             .padding(horizontal = 24.dp),
                         horizontalArrangement = Arrangement.SpaceBetween
                     ) {
-                        AppText(
-                            formatPosition(state.chapterPosition),
-                            style = LegadoTheme.typography.labelSmall,
-                            color = LegadoTheme.colorScheme.onSurfaceVariant
-                        )
-                        AppText(
-                            "${
-                                (state.chapterPosition * 100 / state.chapterLength.coerceAtLeast(
-                                    1
-                                ))
-                            }%",
-                            style = LegadoTheme.typography.labelSmall,
-                            color = LegadoTheme.colorScheme.onSurfaceVariant
-                        )
+                        AppText(formatPosition(state.chapterPosition), style = LegadoTheme.typography.labelSmall, color = LegadoTheme.colorScheme.onSurfaceVariant)
+                        AppText("${(state.chapterPosition * 100 / state.chapterLength.coerceAtLeast(1))}%", style = LegadoTheme.typography.labelSmall, color = LegadoTheme.colorScheme.onSurfaceVariant)
                     }
 
                     Row(
@@ -515,8 +502,8 @@ private fun CoverPage(
     contentPadding: PaddingValues,
     flowingTextModifier: Modifier,
 ) {
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxSize()
             .padding(contentPadding)
             .padding(horizontal = 24.dp),

+ 2 - 3
app/src/main/java/io/legado/app/ui/book/search/ScopeSelectSheet.kt

@@ -24,7 +24,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.data.entities.BookSourcePart
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.SearchBar
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
 import io.legado.app.ui.widget.components.card.SelectionItemCard
@@ -112,8 +111,8 @@ fun ScopeSelectSheet(
             }
         },
     ) {
-        AppColumn(
-        ) {
+        Column {
+
             SearchBar(
                 query = filterText,
                 onQueryChange = { filterText = it },

+ 10 - 29
app/src/main/java/io/legado/app/ui/book/search/SearchScreen.kt

@@ -66,7 +66,6 @@ import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.theme.adaptiveContentPadding
 import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.LoadMoreFooter
@@ -308,8 +307,7 @@ fun SearchScreen(
     AppScaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
-            AppColumn(
-            ) {
+            Column {
                 GlassMediumFlexibleTopAppBar(
                     title = stringResource(R.string.search),
                     navigationIcon = {
@@ -334,8 +332,7 @@ fun SearchScreen(
                         TopBarAnimatedActionButton(
                             checked = state.matchMode == MatchMode.EXACT,
                             onCheckedChange = {
-                                val newMode =
-                                    if (state.matchMode == MatchMode.EXACT) MatchMode.DEFAULT else MatchMode.EXACT
+                                val newMode = if (state.matchMode == MatchMode.EXACT) MatchMode.DEFAULT else MatchMode.EXACT
                                 onIntent(SearchIntent.SetMatchMode(newMode))
                             },
                             iconChecked = AppIcons.PrecisionSearch,
@@ -404,8 +401,8 @@ fun SearchScreen(
             }
         }
     ) { paddingValues ->
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxSize()
                 .padding(paddingValues)
         ) {
@@ -579,15 +576,8 @@ fun SearchScreen(
                         TopFloatingStickyItem(
                             item = if (showResultCountCard || showSourceProgressCard) {
                                 SearchFloatingSummary(
-                                    resultText = if (showResultCountCard) stringResource(
-                                        R.string.search_result_count,
-                                        state.results.size
-                                    ) else null,
-                                    sourceText = if (showSourceProgressCard) stringResource(
-                                        R.string.search_source_progress,
-                                        state.processedSources,
-                                        state.totalSources
-                                    ) else null,
+                                    resultText = if (showResultCountCard) stringResource(R.string.search_result_count, state.results.size) else null,
+                                    sourceText = if (showSourceProgressCard) stringResource(R.string.search_source_progress, state.processedSources, state.totalSources) else null,
                                 )
                             } else {
                                 null
@@ -602,22 +592,13 @@ fun SearchScreen(
                                 contentColor = LegadoTheme.colorScheme.onCardContainer
                             ) {
                                 Row(
-                                    modifier = Modifier.padding(
-                                        horizontal = 12.dp,
-                                        vertical = 8.dp
-                                    ),
+                                    modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp),
                                 ) {
                                     summary.resultText?.let { text ->
-                                        AppText(
-                                            text = text,
-                                            style = LegadoTheme.typography.labelSmallEmphasized
-                                        )
+                                        AppText(text = text, style = LegadoTheme.typography.labelSmallEmphasized)
                                     }
                                     summary.sourceText?.let { text ->
-                                        AppText(
-                                            text = text,
-                                            style = LegadoTheme.typography.labelSmallEmphasized
-                                        )
+                                        AppText(text = text, style = LegadoTheme.typography.labelSmallEmphasized)
                                     }
                                 }
                             }
@@ -691,7 +672,7 @@ fun SearchScreen(
         onDismissRequest = { onIntent(SearchIntent.SetSettingsSheetVisible(false)) },
         title = stringResource(R.string.setting),
     ) {
-        AppColumn(
+        Column(
             verticalArrangement = Arrangement.spacedBy(8.dp)
         ) {
             CompactDropdownSettingItem(

+ 1 - 4
app/src/main/java/io/legado/app/ui/book/search/SearchSourceSection.kt

@@ -29,7 +29,6 @@ import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveHorizonalPadding
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.theme.fadingEdge
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.book.SearchBookGridItem
 import io.legado.app.ui.widget.components.button.series.SmallTonalButton
 import io.legado.app.ui.widget.components.card.TextCard
@@ -50,9 +49,7 @@ fun SearchSourceSection(
 ) {
     if (items.isEmpty()) return
 
-    AppColumn(
-        modifier
-    ) {
+    Column(modifier = modifier) {
         Row(
             modifier = Modifier
                 .fillMaxWidth()

+ 6 - 12
app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt

@@ -55,7 +55,6 @@ import io.legado.app.R
 import io.legado.app.data.entities.SearchContentHistory
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.EmptyMessage
@@ -168,8 +167,7 @@ fun SearchContentScreen(
     AppScaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
-            AppColumn(
-            ) {
+            Column {
                 GlassMediumFlexibleTopAppBar(
                     title = if (searchQuery.isNotBlank() && searchResults.isNotEmpty()) {
                         "共 ${searchResults.size} 条结果"
@@ -260,8 +258,8 @@ fun SearchContentScreen(
             }
         }
     ) { paddingValues ->
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxSize()
                 .padding(paddingValues)
         ) {
@@ -295,7 +293,6 @@ fun SearchContentScreen(
                             onToggleScope = { onIntent(SearchContentIntent.ToggleHistoryScope) }
                         )
                     }
-
                     SearchContentState.EmptyResult -> {
                         EmptyMessage(
                             message = "没有找到相关内容!",
@@ -341,9 +338,7 @@ fun SearchHistoryList(
     onClearHistory: () -> Unit,
     onToggleScope: () -> Unit
 ) {
-    AppColumn(
-        Modifier.fillMaxSize()
-    ) {
+    Column(modifier = Modifier.fillMaxSize()) {
         Box(
             modifier = Modifier
                 .fillMaxWidth()
@@ -445,8 +440,7 @@ fun SearchResultItem(
     ) {
         Box(modifier = Modifier.padding(16.dp)) {
 
-            AppColumn(
-            ) {
+            Column {
                 AppText(
                     text = result.getTitleAnnotatedString(
                         accentColor = LegadoTheme.colorScheme.primary,
@@ -472,7 +466,7 @@ fun SearchResultItem(
                 )
             }
 
-            Row(
+            Row (
                 modifier = Modifier.align(Alignment.TopEnd),
                 horizontalArrangement = Arrangement.spacedBy(4.dp)
             ) {

+ 1 - 4
app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt

@@ -96,7 +96,6 @@ import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.widget.components.ActionItem
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButtonMenu
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.CollapsibleHeader
@@ -889,9 +888,7 @@ fun ChapterItem(
                 .adaptiveHorizontalPadding(vertical = 16.dp),
             verticalAlignment = Alignment.CenterVertically,
         ) {
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
                 Row(verticalAlignment = Alignment.CenterVertically) {
                     if (item.isVip && !item.isPay) {
                         Icon(

+ 10 - 8
app/src/main/java/io/legado/app/ui/book/toc/rule/preview/TxtTocRulePreviewScreen.kt

@@ -52,7 +52,6 @@ import io.legado.app.utils.toastOnUi
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.SearchBar
 import io.legado.app.ui.widget.components.card.GlassCard
@@ -310,10 +309,10 @@ private fun RulePreviewCard(
         modifier = Modifier.fillMaxWidth(),
     ) {
         Box(modifier = Modifier.fillMaxWidth()) {
-            AppColumn(
+            Column(
                 modifier = Modifier
                     .padding(12.dp)
-                    .padding(bottom = 28.dp)
+                    .padding(bottom = 28.dp),
             ) {
                 AppText(
                     text = item.rule.name,
@@ -385,8 +384,8 @@ private fun RulePreviewListItem(
             verticalAlignment = Alignment.CenterVertically,
             horizontalArrangement = Arrangement.SpaceBetween,
         ) {
-            AppColumn(
-                modifier = Modifier.weight(1f)
+            Column(
+                modifier = Modifier.weight(1f),
             ) {
                 Text(
                     text = item.rule.name,
@@ -440,11 +439,12 @@ private fun ChapterListSheetContent(
     item: TocRulePreviewItem,
     onEditRule: (TxtTocRule) -> Unit,
 ) {
-    AppColumn(
-        Modifier
+    Column(
+        modifier = Modifier
             .fillMaxWidth()
-            .padding(16.dp)
+            .padding(16.dp),
     ) {
+        // Header
         Row(
             modifier = Modifier.fillMaxWidth(),
             verticalAlignment = Alignment.CenterVertically,
@@ -478,6 +478,8 @@ private fun ChapterListSheetContent(
         }
 
         Spacer(modifier = Modifier.height(12.dp))
+
+        // Chapter list
         FastScrollLazyColumn(
             modifier = Modifier
                 .fillMaxWidth()

+ 3 - 7
app/src/main/java/io/legado/app/ui/config/ai/AiProviderEditScreen.kt

@@ -34,7 +34,6 @@ import io.legado.app.R
 import io.legado.app.domain.model.AiProtocol
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
@@ -229,8 +228,7 @@ fun AiProviderEditScreen(
         onDismissRequest = { showApiKeyDialog = false },
         title = stringResource(R.string.ai_api_key),
         content = {
-            AppColumn(
-            ) {
+            Column {
                 AppTextField(
                     value = apiKeyDraft,
                     onValueChange = { apiKeyDraft = it },
@@ -240,8 +238,7 @@ fun AiProviderEditScreen(
                     visualTransformation = if (apiKeyVisible) VisualTransformation.None else PasswordVisualTransformation(),
                     keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
                     trailingIcon = {
-                        val image =
-                            if (apiKeyVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
+                        val image = if (apiKeyVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
                         val description = if (apiKeyVisible) {
                             stringResource(R.string.hide_password)
                         } else {
@@ -269,8 +266,7 @@ fun AiProviderEditScreen(
         onDismissRequest = { onIntent(AiProviderEditIntent.DismissModelEditor) },
         title = stringResource(R.string.ai_model_edit),
         content = { model ->
-            io.legado.app.ui.widget.components.AppColumn(
-            ) {
+            Column {
                 AppTextField(
                     value = model.modelName,
                     onValueChange = { onIntent(AiProviderEditIntent.UpdateEditingModelName(it)) },

+ 3 - 5
app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt

@@ -45,7 +45,6 @@ import io.legado.app.lib.permission.Permissions
 import io.legado.app.lib.permission.PermissionsCompat
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.SplicedColumnGroup
@@ -406,8 +405,8 @@ private fun IgnoreItemsSheet(
             )
         },
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .verticalScroll(rememberScrollState()),
             verticalArrangement = Arrangement.spacedBy(8.dp),
@@ -465,8 +464,7 @@ private fun BackupConfigDialogs(
         title = stringResource(R.string.web_dav_account),
         content = {
             auth?.let {
-                io.legado.app.ui.widget.components.AppColumn(
-                ) {
+                Column {
                     AppTextField(
                         value = it.account,
                         onValueChange = { value ->

+ 3 - 5
app/src/main/java/io/legado/app/ui/config/coverConfig/CoverAlbumManageScreen.kt

@@ -48,7 +48,6 @@ import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
@@ -149,7 +148,7 @@ fun CoverAlbumManageScreen(
                     .padding(paddingValues),
                 contentAlignment = Alignment.Center,
             ) {
-                AppColumn(
+                Column(
                     horizontalAlignment = Alignment.CenterHorizontally,
                     verticalArrangement = Arrangement.spacedBy(12.dp),
                 ) {
@@ -255,7 +254,7 @@ private fun CoverAlbumCard(
                     )
                 }
             }
-            AppColumn(
+            Column(
                 modifier = Modifier.weight(1f),
                 verticalArrangement = Arrangement.spacedBy(4.dp),
             ) {
@@ -281,8 +280,7 @@ private fun CoverAlbumCard(
                     )
                 }
             }
-            AppColumn(
-            ) {
+            Column {
                 SmallPlainButton(
                     onClick = onRename,
                     icon = Icons.Default.Edit,

+ 3 - 6
app/src/main/java/io/legado/app/ui/config/coverConfig/CoverAlbumSelectSheet.kt

@@ -25,7 +25,6 @@ import androidx.compose.ui.unit.dp
 import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
 import io.legado.app.ui.widget.components.card.NormalCard
 import io.legado.app.ui.widget.components.icon.AppIcon
@@ -53,8 +52,8 @@ fun CoverAlbumSelectSheet(
             )
         },
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .verticalScroll(rememberScrollState())
                 .padding(vertical = 8.dp),
@@ -136,9 +135,7 @@ private fun CoverAlbumSelectionItem(
                     )
                 }
             }
-            AppColumn(
-                modifier = Modifier.weight(1f)
-            ) {
+            Column(modifier = Modifier.weight(1f)) {
                 AppText(
                     text = name,
                     style = LegadoTheme.typography.titleSmall,

+ 2 - 3
app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt

@@ -15,7 +15,6 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.button.series.MediumTonalButton
 import io.legado.app.ui.widget.components.checkBox.CheckboxItem
@@ -52,8 +51,8 @@ fun CoverRuleConfigSheet(
             )
         }
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 24.dp)
                 .verticalScroll(rememberScrollState()),

+ 3 - 3
app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt

@@ -12,7 +12,6 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.checkBox.CheckboxItem
@@ -33,11 +32,12 @@ fun CheckSourceBottomSheet(
         onDismissRequest = onDismiss,
         title = stringResource(R.string.check_source_config)
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 32.dp)
         ) {
+
             GlassCard {
                 SliderSettingItem(
                     title = stringResource(R.string.check_source_timeout),

+ 2 - 3
app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt

@@ -29,7 +29,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.lib.dialogs.selector
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
@@ -140,8 +139,8 @@ fun DirectLinkUploadBottomSheet(
         },
         onDismissRequest = onDismiss
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 24.dp)
                 .verticalScroll(rememberScrollState())

+ 13 - 16
app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt

@@ -18,7 +18,6 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.AppTextField
 import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
@@ -48,8 +47,8 @@ fun PageKeySheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.custom_page_key)
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(16.dp),
             verticalArrangement = Arrangement.spacedBy(16.dp)
@@ -64,12 +63,11 @@ fun PageKeySheet(
                         if (event.nativeKeyEvent.action == KeyEvent.ACTION_DOWN) {
                             val keyCode = event.nativeKeyEvent.keyCode
                             if (keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_DEL) {
-                                prevKeysDraft =
-                                    if (prevKeysDraft.isEmpty() || prevKeysDraft.endsWith(",")) {
-                                        prevKeysDraft + keyCode.toString()
-                                    } else {
-                                        "$prevKeysDraft,$keyCode"
-                                    }
+                                prevKeysDraft = if (prevKeysDraft.isEmpty() || prevKeysDraft.endsWith(",")) {
+                                    prevKeysDraft + keyCode.toString()
+                                } else {
+                                    "$prevKeysDraft,$keyCode"
+                                }
                                 return@onPreviewKeyEvent true
                             }
                         }
@@ -82,18 +80,17 @@ fun PageKeySheet(
                 value = nextKeysDraft,
                 onValueChange = { nextKeysDraft = it },
                 label = stringResource(R.string.next_page_key),
-                modifier = Modifier
+                modifier = Modifier.Companion
                     .fillMaxWidth()
                     .onPreviewKeyEvent { event ->
                         if (event.nativeKeyEvent.action == KeyEvent.ACTION_DOWN) {
                             val keyCode = event.nativeKeyEvent.keyCode
                             if (keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_DEL) {
-                                nextKeysDraft =
-                                    if (nextKeysDraft.isEmpty() || nextKeysDraft.endsWith(",")) {
-                                        nextKeysDraft + keyCode.toString()
-                                    } else {
-                                        "$nextKeysDraft,$keyCode"
-                                    }
+                                nextKeysDraft = if (nextKeysDraft.isEmpty() || nextKeysDraft.endsWith(",")) {
+                                    nextKeysDraft + keyCode.toString()
+                                } else {
+                                    "$nextKeysDraft,$keyCode"
+                                }
                                 return@onPreviewKeyEvent true
                             }
                         }

+ 3 - 3
app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt

@@ -20,7 +20,6 @@ import androidx.compose.ui.unit.dp
 import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 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.icon.AppIcon
@@ -40,11 +39,12 @@ fun BackgroundImageManageSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.background_image),
     ) { isDark ->
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 24.dp)
         ) {
+
             if (currentPath.isNullOrBlank()) {
                 NormalCard(
                     onClick = { onSelectImage(isDark) },

+ 4 - 4
app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt

@@ -39,7 +39,6 @@ import io.legado.app.ui.main.Launcher5
 import io.legado.app.ui.main.Launcher6
 import io.legado.app.ui.main.LauncherW
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.getCompatDrawable
@@ -61,11 +60,12 @@ fun LauncherIconPickerSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.change_icon)
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
                 .padding(bottom = 24.dp)
         ) {
+
             LazyVerticalGrid(
                 columns = GridCells.Fixed(3),
                 contentPadding = PaddingValues(horizontal = 16.dp),
@@ -196,4 +196,4 @@ object LauncherIcons {
     fun find(value: String?): LauncherIconItem? {
         return list.find { it.value == value }
     }
-}
+}

+ 3 - 4
app/src/main/java/io/legado/app/ui/config/themeConfig/MainNavigationSettingsSheet.kt

@@ -22,7 +22,6 @@ import io.legado.app.R
 import io.legado.app.domain.model.settings.AppShellSettings
 import io.legado.app.ui.main.MainDestination
 import io.legado.app.ui.theme.LegadoTheme
-import io.legado.app.ui.widget.components.AppColumn
 import io.legado.app.ui.widget.components.card.ReorderableSelectionItem
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.CompactClickableSettingItem
@@ -88,10 +87,10 @@ fun MainNavigationSettingsSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.main_navigation_settings),
     ) {
-        AppColumn(
-            Modifier
+        Column(
+            modifier = Modifier
                 .fillMaxWidth()
-                .padding(bottom = 24.dp)
+                .padding(bottom = 24.dp),
         ) {
             CompactDropdownSettingItem(
                 title = stringResource(R.string.default_home_page),

+ 3 - 6
app/src/main/java/io/legado/app/ui/config/themeConfig/NavIconManageSheet.kt

@@ -29,7 +29,6 @@ import io.legado.app.ui.widget.components.icon.AppIcon
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.domain.model.settings.AppShellSettings
-import io.legado.app.ui.widget.components.AppColumn
 
 private data class NavIconDestination(
     val key: String,
@@ -63,11 +62,9 @@ fun NavIconManageSheet(
         onDismissRequest = onDismissRequest,
         title = stringResource(R.string.theme_config_nav_icons),
     ) {
-        AppColumn(
-            Modifier
-                .fillMaxWidth()
-                .padding(bottom = 24.dp)
-        ) {
+        Column(modifier = Modifier
+            .fillMaxWidth()
+            .padding(bottom = 24.dp)) {
             Row(
                 modifier = Modifier
                     .fillMaxWidth()

+ 10 - 0
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigContract.kt

@@ -17,6 +17,7 @@ data class ThemeConfigUiState(
 
 sealed interface ThemeConfigSheet {
     data class Background(val dark: Boolean) : ThemeConfigSheet
+    data class ContainerBackground(val target: ContainerBackgroundTarget, val dark: Boolean) : ThemeConfigSheet
     data object MainNavigation : ThemeConfigSheet
     data object LauncherIcon : ThemeConfigSheet
     data object DividerColor : ThemeConfigSheet
@@ -24,6 +25,8 @@ sealed interface ThemeConfigSheet {
     data object Font : ThemeConfigSheet
 }
 
+enum class ContainerBackgroundTarget { LargeContainer, Item }
+
 sealed interface ThemeConfigDialog {
     data object ResetDefaults : ThemeConfigDialog
     data class TimePicker(
@@ -73,6 +76,12 @@ sealed interface ThemeConfigIntent {
     data class RequestBackgroundImage(val dark: Boolean) : ThemeConfigIntent
     data class SelectBackground(val uri: String, val dark: Boolean) : ThemeConfigIntent
     data class RemoveBackground(val dark: Boolean) : ThemeConfigIntent
+    data class RequestContainerBackgroundImage(val target: ContainerBackgroundTarget, val dark: Boolean) : ThemeConfigIntent
+    data class SelectContainerBackground(val target: ContainerBackgroundTarget, val dark: Boolean, val uri: String) : ThemeConfigIntent
+    data class RemoveContainerBackground(
+        val target: ContainerBackgroundTarget,
+        val dark: Boolean,
+    ) : ThemeConfigIntent
     data class SelectAppFont(val file: FileDoc) : ThemeConfigIntent
     data object ClearAppFont : ThemeConfigIntent
     data class SetFontFolder(val path: String) : ThemeConfigIntent
@@ -92,5 +101,6 @@ sealed interface ThemeConfigEffect {
     data object OpenFontFolder : ThemeConfigEffect
     data class OpenNavigationIcon(val destination: String) : ThemeConfigEffect
     data class OpenBackgroundImage(val dark: Boolean) : ThemeConfigEffect
+    data class OpenContainerBackgroundImage(val target: ContainerBackgroundTarget, val dark: Boolean) : ThemeConfigEffect
     data class ShowToast(val stringRes: Int) : ThemeConfigEffect
 }

+ 11 - 3
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigRouteScreen.kt

@@ -32,6 +32,7 @@ fun ThemeConfigRouteScreen(
     val state by viewModel.uiState.collectAsStateWithLifecycle()
     var pendingNavigationDestination by remember { mutableStateOf<String?>(null) }
     var pendingBackgroundDark by remember { mutableStateOf(false) }
+    var pendingContainerBackground by remember { mutableStateOf<ContainerBackgroundTarget?>(null) }
 
     val fontFolderLauncher = rememberLauncherForActivityResult(
         ActivityResultContracts.OpenDocumentTree()
@@ -66,9 +67,10 @@ fun ThemeConfigRouteScreen(
         ActivityResultContracts.GetContent()
     ) { uri ->
         if (uri != null) {
-            viewModel.onIntent(
-                ThemeConfigIntent.SelectBackground(uri.toString(), pendingBackgroundDark)
-            )
+            pendingContainerBackground?.let { target ->
+                viewModel.onIntent(ThemeConfigIntent.SelectContainerBackground(target, pendingBackgroundDark, uri.toString()))
+                pendingContainerBackground = null
+            } ?: viewModel.onIntent(ThemeConfigIntent.SelectBackground(uri.toString(), pendingBackgroundDark))
         }
     }
 
@@ -85,6 +87,12 @@ fun ThemeConfigRouteScreen(
                     navigationIconLauncher.launch("image/png")
                 }
                 is ThemeConfigEffect.OpenBackgroundImage -> {
+                    pendingContainerBackground = null
+                    pendingBackgroundDark = effect.dark
+                    backgroundImageLauncher.launch("image/*")
+                }
+                is ThemeConfigEffect.OpenContainerBackgroundImage -> {
+                    pendingContainerBackground = effect.target
                     pendingBackgroundDark = effect.dark
                     backgroundImageLauncher.launch("image/*")
                 }

+ 110 - 15
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt

@@ -615,21 +615,6 @@ fun ThemeConfigScreen(
                             )
                         }
                     }
-                    if (!isMiuixEngine) {
-                        SliderSettingItem(
-                            title = stringResource(R.string.container_opacity),
-                            description = stringResource(
-                                R.string.container_opacity_summary,
-                                theme.containerOpacity
-                            ),
-                            value = theme.containerOpacity.toFloat(),
-                            defaultValue = 100f,
-                            valueRange = 0f..100f,
-                            onValueChange = { value ->
-                                updateTheme { it.copy(containerOpacity = value.toInt()) }
-                            }
-                        )
-                    }
                 }
 
                 SplicedColumnGroup(title = stringResource(R.string.background_image)) {
@@ -687,6 +672,91 @@ fun ThemeConfigScreen(
             // Container settings
             item {
                 SplicedColumnGroup(title = stringResource(R.string.theme_manage_section_container)) {
+                    SwitchSettingItem(
+                        title = "容器背景图",
+                        description = "大容器和项目分别使用独立的日间/夜间图片",
+                        checked = theme.enableContainerBackgroundImage,
+                        onCheckedChange = { value ->
+                            updateTheme { it.copy(enableContainerBackgroundImage = value) }
+                        }
+                    )
+                    AnimatedVisibility(visible = theme.enableContainerBackgroundImage) {
+                        Column {
+                            ContainerBackgroundSettingItem(
+                                title = "大容器日间背景图片",
+                                path = theme.largeContainerBackgroundImageLight,
+                                onClick = {
+                                    onIntent(ThemeConfigIntent.RequestContainerBackgroundImage(ContainerBackgroundTarget.LargeContainer, false))
+                                },
+                                onRemove = {
+                                    onIntent(ThemeConfigIntent.RemoveContainerBackground(ContainerBackgroundTarget.LargeContainer, false))
+                                },
+                            )
+                            ContainerBackgroundSettingItem(
+                                title = "大容器夜间背景图片",
+                                path = theme.largeContainerBackgroundImageDark,
+                                onClick = {
+                                    onIntent(ThemeConfigIntent.RequestContainerBackgroundImage(ContainerBackgroundTarget.LargeContainer, true))
+                                },
+                                onRemove = {
+                                    onIntent(ThemeConfigIntent.RemoveContainerBackground(ContainerBackgroundTarget.LargeContainer, true))
+                                },
+                            )
+                            SliderSettingItem(
+                                title = "大容器背景图透明度",
+                                description = "${theme.appColumnBackgroundOpacity}%",
+                                value = theme.appColumnBackgroundOpacity.toFloat(),
+                                defaultValue = 100f,
+                                valueRange = 0f..100f,
+                                onValueChange = { value ->
+                                    updateTheme { it.copy(appColumnBackgroundOpacity = value.toInt()) }
+                                }
+                            )
+                            SliderSettingItem(
+                                title = "项目背景图透明度",
+                                description = "${theme.glassCardBackgroundOpacity}%",
+                                value = theme.glassCardBackgroundOpacity.toFloat(),
+                                defaultValue = 100f,
+                                valueRange = 0f..100f,
+                                onValueChange = { value ->
+                                    updateTheme { it.copy(glassCardBackgroundOpacity = value.toInt()) }
+                                }
+                            )
+                            ContainerBackgroundSettingItem(
+                                title = "项目日间背景图片",
+                                path = theme.itemBackgroundImageLight,
+                                onClick = {
+                                    onIntent(ThemeConfigIntent.RequestContainerBackgroundImage(ContainerBackgroundTarget.Item, false))
+                                },
+                                onRemove = {
+                                    onIntent(ThemeConfigIntent.RemoveContainerBackground(ContainerBackgroundTarget.Item, false))
+                                },
+                            )
+                            ContainerBackgroundSettingItem(
+                                title = "项目夜间背景图片",
+                                path = theme.itemBackgroundImageDark,
+                                onClick = {
+                                    onIntent(ThemeConfigIntent.RequestContainerBackgroundImage(ContainerBackgroundTarget.Item, true))
+                                },
+                                onRemove = {
+                                    onIntent(ThemeConfigIntent.RemoveContainerBackground(ContainerBackgroundTarget.Item, true))
+                                },
+                            )
+                        }
+                    }
+                    SliderSettingItem(
+                            title = stringResource(R.string.container_opacity),
+                            description = stringResource(
+                                R.string.container_opacity_summary,
+                                theme.containerOpacity
+                            ),
+                            value = theme.containerOpacity.toFloat(),
+                            defaultValue = 100f,
+                            valueRange = 0f..100f,
+                            onValueChange = { value ->
+                                updateTheme { it.copy(containerOpacity = value.toInt()) }
+                            }
+                    )
                     SwitchSettingItem(
                         title = stringResource(R.string.disable_spliced_group_corner_radius),
                         description = stringResource(R.string.disable_spliced_group_corner_radius_summary),
@@ -958,6 +1028,31 @@ fun ThemeConfigScreen(
 
 }
 
+@Composable
+private fun ContainerBackgroundSettingItem(
+    title: String,
+    path: String?,
+    onClick: () -> Unit,
+    onRemove: () -> Unit,
+) {
+    ClickableSettingItem(
+        title = title,
+        description = if (path.isNullOrBlank()) "选择图片" else "已选择",
+        onClick = onClick,
+        trailingContent = if (path.isNullOrBlank()) {
+            null
+        } else {
+            {
+                SmallPlainButton(
+                    onClick = onRemove,
+                    icon = Icons.Default.Delete,
+                    contentDescription = stringResource(R.string.clear),
+                )
+            }
+        },
+    )
+}
+
 @Composable
 private fun BaseCardBorderColorSettingItem(
     title: String,

+ 119 - 17
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigViewModel.kt

@@ -151,6 +151,16 @@ class ThemeConfigViewModel(
             )
             is ThemeConfigIntent.SelectBackground -> setBackground(intent.uri, intent.dark)
             is ThemeConfigIntent.RemoveBackground -> removeBackground(intent.dark)
+            is ThemeConfigIntent.RequestContainerBackgroundImage -> _effects.tryEmit(ThemeConfigEffect.OpenContainerBackgroundImage(intent.target, intent.dark))
+            is ThemeConfigIntent.SelectContainerBackground -> setContainerBackground(
+                uriString = intent.uri,
+                target = intent.target,
+                dark = intent.dark,
+            )
+            is ThemeConfigIntent.RemoveContainerBackground -> removeContainerBackground(
+                target = intent.target,
+                dark = intent.dark,
+            )
             is ThemeConfigIntent.SelectAppFont -> setAppFont(intent.file)
             ThemeConfigIntent.ClearAppFont -> clearAppFont()
             is ThemeConfigIntent.SetFontFolder -> viewModelScope.launch {
@@ -193,7 +203,14 @@ class ThemeConfigViewModel(
             val defaultTheme = ThemeSettings()
             val currentTheme = _uiState.value.theme
 
-            listOf(currentTheme.backgroundImageLight, currentTheme.backgroundImageDark)
+            listOf(
+                currentTheme.backgroundImageLight,
+                currentTheme.backgroundImageDark,
+                currentTheme.largeContainerBackgroundImageLight,
+                currentTheme.largeContainerBackgroundImageDark,
+                currentTheme.itemBackgroundImageLight,
+                currentTheme.itemBackgroundImageDark,
+            )
                 .filterNotNull()
                 .map(::File)
                 .filter { it.absolutePath.startsWith(appCtx.externalFiles.absolutePath) }
@@ -345,24 +362,113 @@ class ThemeConfigViewModel(
     private fun setBackground(uriString: String, dark: Boolean) {
         viewModelScope.launch(Dispatchers.IO) {
             runCatching {
-                val uri = Uri.parse(uriString)
-                val fileDoc = FileDoc.fromUri(uri, false)
-                val suffix = fileDoc.name.substringAfterLast(".", "jpg")
-                val md5 = uri.inputStream(appCtx).getOrThrow().use(MD5Utils::md5Encode)
                 val preferenceKey = if (dark) PreferKey.bgImageN else PreferKey.bgImage
-                val folder = File(appCtx.externalFiles, preferenceKey)
-                val file = File(folder, "$md5.$suffix")
-                if (!file.exists()) {
-                    FileUtils.createFileIfNotExist(file.absolutePath)
-                    uri.inputStream(appCtx).getOrThrow().use { input ->
-                        FileOutputStream(file).use(input::copyTo)
+                updateBackgroundPath(
+                    dark = dark,
+                    newPath = copyBackgroundImage(uriString, preferenceKey),
+                )
+            }.onFailure(Throwable::printStackTrace)
+        }
+    }
+
+    private fun setContainerBackground(
+        uriString: String,
+        target: ContainerBackgroundTarget,
+        dark: Boolean,
+    ) {
+        viewModelScope.launch(Dispatchers.IO) {
+            runCatching {
+                val folderName = buildString {
+                    append("container_background/")
+                    append(if (target == ContainerBackgroundTarget.LargeContainer) "large" else "item")
+                    append(if (dark) "_dark" else "_light")
+                }
+                val newPath = copyBackgroundImage(uriString, folderName)
+                val oldPath = when (target) {
+                    ContainerBackgroundTarget.LargeContainer -> if (dark) {
+                        _uiState.value.theme.largeContainerBackgroundImageDark
+                    } else {
+                        _uiState.value.theme.largeContainerBackgroundImageLight
+                    }
+                    ContainerBackgroundTarget.Item -> if (dark) {
+                        _uiState.value.theme.itemBackgroundImageDark
+                    } else {
+                        _uiState.value.theme.itemBackgroundImageLight
                     }
                 }
-                updateBackgroundPath(dark, file.absolutePath)
+                themeSettingsGateway.update { theme ->
+                    when (target) {
+                        ContainerBackgroundTarget.LargeContainer -> if (dark) {
+                            theme.copy(largeContainerBackgroundImageDark = newPath)
+                        } else {
+                            theme.copy(largeContainerBackgroundImageLight = newPath)
+                        }
+                        ContainerBackgroundTarget.Item -> if (dark) {
+                            theme.copy(itemBackgroundImageDark = newPath)
+                        } else {
+                            theme.copy(itemBackgroundImageLight = newPath)
+                        }
+                    }
+                }
+                deleteOwnedBackground(oldPath, newPath)
             }.onFailure(Throwable::printStackTrace)
         }
     }
 
+    private fun copyBackgroundImage(uriString: String, folderName: String): String {
+        val uri = Uri.parse(uriString)
+        val fileDoc = FileDoc.fromUri(uri, false)
+        val suffix = if (fileDoc.name.endsWith(".9.png", ignoreCase = true)) {
+            "9.png"
+        } else {
+            fileDoc.name.substringAfterLast(".", "jpg")
+        }
+        val md5 = uri.inputStream(appCtx).getOrThrow().use(MD5Utils::md5Encode)
+        val file = File(File(appCtx.externalFiles, folderName), "$md5.$suffix")
+        if (!file.exists()) {
+            FileUtils.createFileIfNotExist(file.absolutePath)
+            uri.inputStream(appCtx).getOrThrow().use { input ->
+                FileOutputStream(file).use(input::copyTo)
+            }
+        }
+        return file.absolutePath
+    }
+
+    private fun removeContainerBackground(
+        target: ContainerBackgroundTarget,
+        dark: Boolean,
+    ) {
+        viewModelScope.launch(Dispatchers.IO) {
+            var oldPath: String? = null
+            themeSettingsGateway.update { theme ->
+                when (target) {
+                    ContainerBackgroundTarget.LargeContainer -> if (dark) {
+                        oldPath = theme.largeContainerBackgroundImageDark
+                        theme.copy(largeContainerBackgroundImageDark = null)
+                    } else {
+                        oldPath = theme.largeContainerBackgroundImageLight
+                        theme.copy(largeContainerBackgroundImageLight = null)
+                    }
+                    ContainerBackgroundTarget.Item -> if (dark) {
+                        oldPath = theme.itemBackgroundImageDark
+                        theme.copy(itemBackgroundImageDark = null)
+                    } else {
+                        oldPath = theme.itemBackgroundImageLight
+                        theme.copy(itemBackgroundImageLight = null)
+                    }
+                }
+            }
+            deleteOwnedBackground(oldPath, null)
+        }
+    }
+
+    private fun deleteOwnedBackground(oldPath: String?, newPath: String?) {
+        if (oldPath == null || oldPath == newPath) return
+        File(oldPath)
+            .takeIf { it.absolutePath.startsWith(appCtx.externalFiles.absolutePath) }
+            ?.delete()
+    }
+
     private fun removeBackground(dark: Boolean) {
         viewModelScope.launch(Dispatchers.IO) { updateBackgroundPath(dark, null) }
     }
@@ -373,11 +479,7 @@ class ThemeConfigViewModel(
         } else {
             _uiState.value.theme.backgroundImageLight
         }
-        if (oldPath != newPath && oldPath != null) {
-            File(oldPath)
-                .takeIf { it.absolutePath.contains(appCtx.externalFiles.absolutePath) }
-                ?.delete()
-        }
+        deleteOwnedBackground(oldPath, newPath)
         themeSettingsGateway.update {
             if (dark) it.copy(backgroundImageDark = newPath)
             else it.copy(backgroundImageLight = newPath)

Некоторые файлы не были показаны из-за большого количества измененных файлов