HapeLee 7 месяцев назад
Родитель
Сommit
01fb34a1bd
100 измененных файлов с 2542 добавлено и 1423 удалено
  1. 5 0
      app/build.gradle.kts
  2. 14 0
      app/src/main/java/io/legado/app/data/dao/BookDao.kt
  3. 9 9
      app/src/main/java/io/legado/app/ui/about/AboutScreen.kt
  4. 11 10
      app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt
  5. 6 10
      app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt
  6. 35 38
      app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt
  7. 7 7
      app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt
  8. 33 32
      app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt
  9. 11 11
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt
  10. 50 53
      app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt
  11. 16 19
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt
  12. 24 23
      app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt
  13. 9 9
      app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt
  14. 3 4
      app/src/main/java/io/legado/app/ui/config/ConfigNavScreen.kt
  15. 21 23
      app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt
  16. 3 4
      app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt
  17. 4 3
      app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt
  18. 11 7
      app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt
  19. 6 5
      app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt
  20. 17 16
      app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt
  21. 24 17
      app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt
  22. 10 9
      app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt
  23. 3 6
      app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt
  24. 4 3
      app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt
  25. 4 3
      app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt
  26. 3 0
      app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt
  27. 22 14
      app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt
  28. 15 17
      app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt
  29. 7 7
      app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt
  30. 9 9
      app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt
  31. 4 4
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  32. 34 19
      app/src/main/java/io/legado/app/ui/main/MainDestination.kt
  33. 22 94
      app/src/main/java/io/legado/app/ui/main/MainScreen.kt
  34. 17 16
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookItem.kt
  35. 4 0
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookShelfItem.kt
  36. 4 3
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt
  37. 27 39
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt
  38. 4 3
      app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt
  39. 39 30
      app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt
  40. 88 59
      app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt
  41. 16 15
      app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt
  42. 27 49
      app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt
  43. 29 29
      app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt
  44. 7 7
      app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt
  45. 23 19
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt
  46. 12 12
      app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt
  47. 19 0
      app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt
  48. 67 10
      app/src/main/java/io/legado/app/ui/theme/AppTheme.kt
  49. 4 4
      app/src/main/java/io/legado/app/ui/theme/HazeStyle.kt
  50. 85 0
      app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt
  51. 12 0
      app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt
  52. 44 0
      app/src/main/java/io/legado/app/ui/theme/Typography.kt
  53. 48 0
      app/src/main/java/io/legado/app/ui/theme/hazeStyle/HazeLegado.kt
  54. 6 5
      app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt
  55. 3 3
      app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt
  56. 56 0
      app/src/main/java/io/legado/app/ui/widget/components/AppFloatingActionButton.kt
  57. 93 0
      app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt
  58. 67 44
      app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt
  59. 2 2
      app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt
  60. 0 113
      app/src/main/java/io/legado/app/ui/widget/components/GlassMediumFlexibleTopAppBar.kt
  61. 5 4
      app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt
  62. 34 0
      app/src/main/java/io/legado/app/ui/widget/components/IconSwitch.kt
  63. 2 2
      app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt
  64. 3 3
      app/src/main/java/io/legado/app/ui/widget/components/SelectionBottomBar.kt
  65. 25 16
      app/src/main/java/io/legado/app/ui/widget/components/SplicedColumnGroup.kt
  66. 12 11
      app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt
  67. 8 7
      app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt
  68. 2 2
      app/src/main/java/io/legado/app/ui/widget/components/button/AlertButton.kt
  69. 4 4
      app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedActionButton.kt
  70. 2 2
      app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedTextButton.kt
  71. 57 0
      app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt
  72. 31 16
      app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt
  73. 4 3
      app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt
  74. 78 51
      app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt
  75. 104 32
      app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt
  76. 48 19
      app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt
  77. 75 0
      app/src/main/java/io/legado/app/ui/widget/components/card/SettingCard.kt
  78. 9 17
      app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt
  79. 4 3
      app/src/main/java/io/legado/app/ui/widget/components/checkBox/CheckboxItem.kt
  80. 18 4
      app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt
  81. 8 7
      app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt
  82. 9 9
      app/src/main/java/io/legado/app/ui/widget/components/dialog/TextListInputDialog.kt
  83. 4 3
      app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt
  84. 6 5
      app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt
  85. 10 9
      app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt
  86. 37 0
      app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt
  87. 12 11
      app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt
  88. 11 24
      app/src/main/java/io/legado/app/ui/widget/components/list/ListScaffold.kt
  89. 2 1
      app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt
  90. 7 7
      app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt
  91. 15 27
      app/src/main/java/io/legado/app/ui/widget/components/rules/RuleListScaffold.kt
  92. 30 16
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/ClickableSettingItem.kt
  93. 2 2
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt
  94. 101 40
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt
  95. 61 28
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt
  96. 10 9
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/SettingItem.kt
  97. 179 68
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt
  98. 41 14
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt
  99. 63 0
      app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt
  100. 150 0
      app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt

+ 5 - 0
app/build.gradle.kts

@@ -286,4 +286,9 @@ dependencies {
     implementation(libs.material.kolor)
     implementation(libs.haze.core)
     implementation(libs.haze.materials)
+    implementation(libs.miuix)
+    implementation(libs.miuix.icons)
+    implementation(libs.capsule)
+    implementation(libs.backdrop)
+    implementation(libs.timber)
 }

+ 14 - 0
app/src/main/java/io/legado/app/data/dao/BookDao.kt

@@ -82,6 +82,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -113,6 +114,7 @@ interface BookDao {
         durChapterPos,
         latestChapterTitle,
         latestChapterTime,
+        lastCheckCount,
         totalChapterNum,
         durChapterIndex,
         type,
@@ -141,6 +143,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -169,6 +172,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -202,6 +206,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -236,6 +241,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -265,6 +271,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -293,6 +300,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -321,6 +329,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -350,6 +359,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -378,6 +388,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -406,6 +417,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -434,6 +446,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,
@@ -462,6 +475,7 @@ interface BookDao {
             durChapterPos,
             latestChapterTitle,
             latestChapterTime,
+            lastCheckCount,
             totalChapterNum,
             durChapterIndex,
             type,

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

@@ -15,9 +15,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.FilledTonalIconButton
 import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.MaterialTheme.colorScheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -31,13 +29,15 @@ import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import io.legado.app.R
 import io.legado.app.constant.AppConst.appInfo
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.settingItem.SettingItem
+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
 
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -59,7 +59,7 @@ fun AboutScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = { Text(stringResource(R.string.about)) },
+                title = stringResource(R.string.about),
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBack)
                 },
@@ -81,9 +81,9 @@ fun AboutScreen(
                     .width(160.dp)
                     .align(Alignment.CenterHorizontally)
             )
-            Text(
+            AppText(
                 text = stringResource(R.string.app_name),
-                style = MaterialTheme.typography.bodyLarge,
+                style = LegadoTheme.typography.bodyLarge,
                 fontSize = 18.sp,
                 fontWeight = FontWeight.Bold,
                 modifier = Modifier
@@ -98,9 +98,9 @@ fun AboutScreen(
                     .fillMaxWidth()
                     .wrapContentWidth(Alignment.CenterHorizontally)
                     .padding(vertical = 4.dp))
-            Text(
+            AppText(
                 text = stringResource(R.string.about_description),
-                style = MaterialTheme.typography.bodyLarge,
+                style = LegadoTheme.typography.bodyLarge,
                 fontSize = 12.sp,
                 modifier = Modifier
                     .fillMaxWidth()

+ 11 - 10
app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt

@@ -18,7 +18,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -31,7 +30,9 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.constant.AppLog
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.LogUtils
 import java.util.Date
 
@@ -52,9 +53,9 @@ fun AppLogSheet(
                 .padding(horizontal = 16.dp, vertical = 8.dp),
             verticalAlignment = Alignment.CenterVertically
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.log),
-                style = MaterialTheme.typography.titleLarge,
+                style = LegadoTheme.typography.titleLarge,
                 modifier = Modifier.weight(1f)
             )
             IconButton(onClick = {
@@ -82,17 +83,17 @@ fun AppLogSheet(
     showStackTrace?.let { stackTrace ->
         AlertDialog(
             onDismissRequest = { showStackTrace = null },
-            title = { Text("Log") },
+            title = { AppText("Log") },
             text = {
                 SelectionContainer {
                     Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
-                        Text(text = stackTrace, style = MaterialTheme.typography.bodySmall)
+                        AppText(text = stackTrace, style = LegadoTheme.typography.bodySmall)
                     }
                 }
             },
             confirmButton = {
                 TextButton(onClick = { showStackTrace = null }) {
-                    Text(stringResource(android.R.string.ok))
+                    AppText(stringResource(android.R.string.ok))
                 }
             }
         )
@@ -110,14 +111,14 @@ private fun LogItem(
             .clickable(onClick = onClick)
             .padding(16.dp)
     ) {
-        Text(
+        AppText(
             text = LogUtils.logTimeFormat.format(Date(item.first)),
-            style = MaterialTheme.typography.labelMedium,
+            style = LegadoTheme.typography.labelMedium,
             color = MaterialTheme.colorScheme.outline
         )
-        Text(
+        AppText(
             text = item.second,
-            style = MaterialTheme.typography.bodyMedium,
+            style = LegadoTheme.typography.bodyMedium,
             modifier = Modifier.padding(top = 4.dp)
         )
     }

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

@@ -26,7 +26,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
@@ -41,8 +40,6 @@ import io.legado.app.data.entities.Bookmark
 import io.legado.app.ui.widget.CollapsibleHeader
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.EmptyMessageView
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SearchBarSection
 import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet
 import io.legado.app.ui.widget.components.bookmark.BookmarkItem
@@ -51,6 +48,9 @@ import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
 import io.legado.app.ui.widget.components.lazylist.Scroller
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+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 org.koin.androidx.compose.koinViewModel
 
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
@@ -98,11 +98,7 @@ fun AllBookmarkScreen(
         topBar = {
             Column {
                 GlassMediumFlexibleTopAppBar(
-                    title = {
-                        Text(
-                            text = "所有书签"
-                        )
-                    },
+                    title = "所有书签",
                     scrollBehavior = scrollBehavior,
                     navigationIcon = {
                         TopbarNavigationButton(onClick = onBack)
@@ -132,7 +128,7 @@ fun AllBookmarkScreen(
                             onDismissRequest = { showMenu = false }
                         ) {
                             RoundDropdownMenuItem(
-                                text = { Text("导出 JSON") },
+                                text = { AppText("导出 JSON") },
                                 onClick = {
                                     showMenu = false
                                     pendingExportIsMd = false
@@ -140,7 +136,7 @@ fun AllBookmarkScreen(
                                 }
                             )
                             RoundDropdownMenuItem(
-                                text = { Text("导出 Markdown") },
+                                text = { AppText("导出 Markdown") },
                                 onClick = {
                                     showMenu = false
                                     pendingExportIsMd = true

+ 35 - 38
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt

@@ -52,7 +52,6 @@ import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.Slider
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
 import androidx.compose.material3.pulltorefresh.PullToRefreshBox
 import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
 import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
@@ -79,12 +78,10 @@ import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.data.entities.rule.ExploreKind
 import io.legado.app.model.BookShelfState
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.responsiveHazeEffect
 import io.legado.app.ui.theme.responsiveHazeSource
-import io.legado.app.ui.widget.components.AnimatedTextLine
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SearchBarSection
 import io.legado.app.ui.widget.components.button.AnimatedTextButton
 import io.legado.app.ui.widget.components.button.TopBarActionButton
@@ -94,6 +91,9 @@ import io.legado.app.ui.widget.components.cover.Cover
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+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 kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import org.koin.androidx.compose.koinViewModel
@@ -194,16 +194,16 @@ fun ExploreShowScreen(
                 verticalAlignment = Alignment.CenterVertically,
                 horizontalArrangement = Arrangement.Center
             ) {
-                Text(
+                AppText(
                     text = "布局列数",
-                    style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold)
+                    style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold)
                 )
 
                 Spacer(modifier = Modifier.width(12.dp))
 
                 TextCard(
                     text = "$gridColumnCount 列",
-                    textStyle = MaterialTheme.typography.titleSmall,
+                    textStyle = LegadoTheme.typography.titleSmall,
                     verticalPadding = 4.dp,
                     horizontalPadding = 12.dp,
                     cornerRadius = 12.dp
@@ -229,7 +229,7 @@ fun ExploreShowScreen(
                     .fillMaxWidth()
                     .padding(horizontal = 16.dp)
             ) {
-                Text("完成")
+                AppText("完成")
             }
         }
     }
@@ -294,13 +294,7 @@ fun ExploreShowScreen(
                 modifier = Modifier.responsiveHazeEffect(
                     state = hazeState
                 ),
-                title = {
-                    AnimatedTextLine(
-                        selectedTitle ?: title,
-                        maxLines = 1,
-                        overflow = TextOverflow.Ellipsis
-                    )
-                },
+                title = selectedTitle ?: title,
                 colors = GlassTopAppBarDefaults.glassColors(),
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBack)
@@ -346,7 +340,7 @@ fun ExploreShowScreen(
                         onDismissRequest = { showMenu = false }
                     ) {
                         RoundDropdownMenuItem(
-                            text = { Text("全部显示") },
+                            text = { AppText("全部显示") },
                             onClick = {
                                 viewModel.setFilterState(BookFilterState.SHOW_ALL)
                                 showMenu = false
@@ -358,7 +352,7 @@ fun ExploreShowScreen(
                         )
 
                         RoundDropdownMenuItem(
-                            text = { Text("隐藏已在书架的同源书籍") },
+                            text = { AppText("隐藏已在书架的同源书籍") },
                             onClick = {
                                 viewModel.setFilterState(BookFilterState.HIDE_IN_SHELF)
                                 showMenu = false
@@ -370,7 +364,7 @@ fun ExploreShowScreen(
                         )
 
                         RoundDropdownMenuItem(
-                            text = { Text("隐藏已在书架的非同源书籍") },
+                            text = { AppText("隐藏已在书架的非同源书籍") },
                             onClick = {
                                 viewModel.setFilterState(BookFilterState.HIDE_SAME_NAME_AUTHOR)
                                 showMenu = false
@@ -382,7 +376,7 @@ fun ExploreShowScreen(
                         )
 
                         RoundDropdownMenuItem(
-                            text = { Text("只显示不在书架的书籍") },
+                            text = { AppText("只显示不在书架的书籍") },
                             onClick = {
                                 viewModel.setFilterState(BookFilterState.SHOW_NOT_IN_SHELF_ONLY)
                                 showMenu = false
@@ -509,7 +503,7 @@ fun KindGridItem(
         enabled = isClickable,
         selected = isSelected,
         label = {
-            Text(
+            AppText(
                 text = kind.title,
                 fontSize = 12.sp,
                 modifier = Modifier.fillMaxWidth(),
@@ -576,32 +570,32 @@ fun ExploreBookItem(
             .weight(1f)
             .align(Alignment.CenterVertically)) {
 
-            Text(
+            AppText(
                 text = book.name,
-                style = MaterialTheme.typography.titleSmall,
+                style = LegadoTheme.typography.titleSmall,
                 maxLines = 1,
                 overflow = TextOverflow.Ellipsis
             )
 
             Row {
-                Text(
+                AppText(
                     text = book.author,
-                    style = MaterialTheme.typography.bodySmall,
+                    style = LegadoTheme.typography.bodySmall,
                     maxLines = 1
                 )
 
                 val latestChapter = book.latestChapterTitle
                 if (!latestChapter.isNullOrEmpty()) {
-                    Text(
+                    AppText(
                         text = " • ",
-                        style = MaterialTheme.typography.bodySmall,
+                        style = LegadoTheme.typography.bodySmall,
                         color = Color.Gray,
                         maxLines = 1
                     )
 
-                    Text(
+                    AppText(
                         text = "最新: $latestChapter",
-                        style = MaterialTheme.typography.bodySmall,
+                        style = LegadoTheme.typography.bodySmall,
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
                     )
@@ -612,9 +606,9 @@ fun ExploreBookItem(
 
             val intro = book.intro?.replace("\\s+".toRegex(), "") ?: ""
             if (intro.isNotEmpty()) {
-                Text(
+                AppText(
                     text = intro,
-                    style = MaterialTheme.typography.labelSmall,
+                    style = LegadoTheme.typography.labelSmall,
                     color = Color.Gray,
                     maxLines = 2,
                     minLines = 2,
@@ -654,9 +648,12 @@ fun ExploreBookGridItem(
 
     val content: (@Composable RowScope.() -> Unit)? = if (!badgeText.isNullOrBlank()) {
         {
-            Text(
+            AppText(
                 text = badgeText,
-                style = MaterialTheme.typography.labelSmall.copy(fontWeight = FontWeight.Bold, fontSize = 9.sp)
+                style = LegadoTheme.typography.labelSmall.copy(
+                    fontWeight = FontWeight.Bold,
+                    fontSize = 9.sp
+                )
             )
         }
     } else {
@@ -681,9 +678,9 @@ fun ExploreBookGridItem(
 
         Spacer(modifier = Modifier.height(4.dp))
 
-        Text(
+        AppText(
             text = book.name,
-            style = MaterialTheme.typography.bodySmall,
+            style = LegadoTheme.typography.bodySmall,
             fontWeight = FontWeight.Bold,
             maxLines = 2,
             overflow = TextOverflow.Ellipsis
@@ -698,10 +695,10 @@ fun TagChip(text: String) {
         color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.5f),
         shape = RoundedCornerShape(4.dp)
     ) {
-        Text(
+        AppText(
             text = text,
             modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
-            style = MaterialTheme.typography.labelSmall,
+            style = LegadoTheme.typography.labelSmall,
             color = MaterialTheme.colorScheme.primary
         )
     }
@@ -742,13 +739,13 @@ fun LoadMoreFooter(
                 },
                 label = "FooterTextChange"
             ) { text ->
-                Text(
+                AppText(
                     text = text,
                     color = when {
                         errorMsg != null -> Color.Red
                         else -> Color.Gray
                     },
-                    style = MaterialTheme.typography.bodySmall
+                    style = LegadoTheme.typography.bodySmall
                 )
             }
 

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

@@ -18,11 +18,9 @@ import androidx.compose.material.icons.filled.Restore
 import androidx.compose.material3.Button
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.OutlinedIconButton
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
@@ -38,10 +36,12 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.data.entities.BookGroup
 import io.legado.app.lib.dialogs.alert
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.cover.Cover
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem
 import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.FileUtils
 import io.legado.app.utils.MD5Utils
 import io.legado.app.utils.SelectImageContract
@@ -113,9 +113,9 @@ fun GroupEditContent(
             .verticalScroll(rememberScrollState()),
         horizontalAlignment = Alignment.CenterHorizontally
     ) {
-        Text(
+        AppText(
             text = stringResource(R.string.group_edit),
-            style = MaterialTheme.typography.titleLarge,
+            style = LegadoTheme.typography.titleLarge,
             modifier = Modifier.padding(vertical = 16.dp)
         )
 
@@ -138,7 +138,7 @@ fun GroupEditContent(
                 OutlinedTextField(
                     value = groupName,
                     onValueChange = { groupName = it },
-                    label = { Text(stringResource(R.string.group_name)) },
+                    label = { AppText(stringResource(R.string.group_name)) },
                     modifier = Modifier.fillMaxWidth(),
                     singleLine = true
                 )
@@ -206,7 +206,7 @@ fun GroupEditContent(
 
             Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                 OutlinedButton(onClick = onDismissRequest) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
                 Button(onClick = {
                     if (groupName.isEmpty()) {
@@ -235,7 +235,7 @@ fun GroupEditContent(
                         }
                     }
                 }) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             }
         }

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

@@ -51,7 +51,6 @@ import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.RadioButton
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.pulltorefresh.PullToRefreshBox
 import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
@@ -80,6 +79,7 @@ import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.Server
 import io.legado.app.help.config.AppConfig
 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.EmptyMessageView
 import io.legado.app.ui.widget.components.SelectionActions
@@ -89,6 +89,7 @@ import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.list.ListScaffold
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.ArchiveUtils
 import io.legado.app.utils.ConvertUtils
 import io.legado.app.utils.FileDoc
@@ -157,19 +158,19 @@ fun RemoteBookScreen(
             is RemoteBookDialog.DownloadArchive -> {
                 AlertDialog(
                     onDismissRequest = { dialogState = null },
-                    title = { Text(stringResource(R.string.draw)) },
-                    text = { Text(stringResource(R.string.archive_not_found)) },
+                    title = { AppText(stringResource(R.string.draw)) },
+                    text = { AppText(stringResource(R.string.archive_not_found)) },
                     confirmButton = {
                         OutlinedButton(onClick = {
                             scope.launch { viewModel.addToBookshelf(setOf(state.remoteBook)) }
                             dialogState = null
                         }) {
-                            Text(stringResource(android.R.string.ok))
+                            AppText(stringResource(android.R.string.ok))
                         }
                     },
                     dismissButton = {
                         TextButton(onClick = { dialogState = null }) {
-                            Text(stringResource(android.R.string.cancel))
+                            AppText(stringResource(android.R.string.cancel))
                         }
                     }
                 )
@@ -178,19 +179,19 @@ fun RemoteBookScreen(
             is RemoteBookDialog.ReImport -> {
                 AlertDialog(
                     onDismissRequest = { dialogState = null },
-                    title = { Text("是否重新加入书架?") },
-                    text = { Text("将会覆盖书籍") },
+                    title = { AppText("是否重新加入书架?") },
+                    text = { AppText("将会覆盖书籍") },
                     confirmButton = {
                         OutlinedButton(onClick = {
                             scope.launch { viewModel.addToBookshelf(setOf(state.remoteBook)) }
                             dialogState = null
                         }) {
-                            Text(stringResource(android.R.string.ok))
+                            AppText(stringResource(android.R.string.ok))
                         }
                     },
                     dismissButton = {
                         TextButton(onClick = { dialogState = null }) {
-                            Text(stringResource(android.R.string.cancel))
+                            AppText(stringResource(android.R.string.cancel))
                         }
                     }
                 )
@@ -259,7 +260,7 @@ fun RemoteBookScreen(
         },
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
-                text = { Text("按名称排序") },
+                text = { AppText("按名称排序") },
                 onClick = {
                     viewModel.toggleSort(RemoteBookSort.Name)
                     dismiss()
@@ -271,7 +272,7 @@ fun RemoteBookScreen(
                 }
             )
             RoundDropdownMenuItem(
-                text = { Text("按时间排序") },
+                text = { AppText("按时间排序") },
                 onClick = {
                     viewModel.toggleSort(RemoteBookSort.Default)
                     dismiss()
@@ -381,9 +382,9 @@ private fun ServersSheetContent(
             verticalAlignment = Alignment.CenterVertically,
             horizontalArrangement = Arrangement.SpaceBetween
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.server_config),
-                style = MaterialTheme.typography.titleLarge
+                style = LegadoTheme.typography.titleLarge
             )
             IconButton(onClick = onAdd) {
                 Icon(Icons.Default.Add, contentDescription = "添加")
@@ -447,9 +448,9 @@ private fun ServerItem(
         ListItem(
             modifier = Modifier.animateContentSize(),
             headlineContent = {
-                Text(
+                AppText(
                     text = name,
-                    style = MaterialTheme.typography.titleMedium,
+                    style = LegadoTheme.typography.titleMedium,
                     maxLines = 1,
                     overflow = TextOverflow.Ellipsis
                 )
@@ -462,9 +463,9 @@ private fun ServerItem(
             },
             supportingContent = url?.let {
                 {
-                    Text(
+                    AppText(
                         text = it,
-                        style = MaterialTheme.typography.bodySmall,
+                        style = LegadoTheme.typography.bodySmall,
                         color = MaterialTheme.colorScheme.onSurfaceVariant,
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
@@ -514,16 +515,16 @@ private fun ServerConfigSheetContent(
             .padding(16.dp)
             .verticalScroll(rememberScrollState())
     ) {
-        Text(
+        AppText(
             text = if (server == null) "添加服务器" else "编辑服务器",
-            style = MaterialTheme.typography.titleLarge,
+            style = LegadoTheme.typography.titleLarge,
             modifier = Modifier.padding(bottom = 16.dp)
         )
 
         OutlinedTextField(
             value = name,
             onValueChange = { name = it },
-            label = { Text("名称") },
+            label = { AppText("名称") },
             modifier = Modifier.fillMaxWidth(),
             singleLine = true
         )
@@ -531,7 +532,7 @@ private fun ServerConfigSheetContent(
         OutlinedTextField(
             value = url,
             onValueChange = { url = it },
-            label = { Text("URL") },
+            label = { AppText("URL") },
             modifier = Modifier.fillMaxWidth(),
             singleLine = true
         )
@@ -539,7 +540,7 @@ private fun ServerConfigSheetContent(
         OutlinedTextField(
             value = username,
             onValueChange = { username = it },
-            label = { Text("用户名") },
+            label = { AppText("用户名") },
             modifier = Modifier.fillMaxWidth(),
             singleLine = true
         )
@@ -547,7 +548,7 @@ private fun ServerConfigSheetContent(
         OutlinedTextField(
             value = password,
             onValueChange = { password = it },
-            label = { Text("密码") },
+            label = { AppText("密码") },
             modifier = Modifier.fillMaxWidth(),
             singleLine = true,
             visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
@@ -571,7 +572,7 @@ private fun ServerConfigSheetContent(
                 onClick = onCancel,
                 modifier = Modifier.weight(1f)
             ) {
-                Text(stringResource(android.R.string.cancel))
+                AppText(stringResource(android.R.string.cancel))
             }
             Button(
                 onClick = {
@@ -587,7 +588,7 @@ private fun ServerConfigSheetContent(
                 modifier = Modifier.weight(1f),
                 enabled = name.isNotBlank() && url.isNotBlank()
             ) {
-                Text("保存")
+                AppText("保存")
             }
         }
     }
@@ -625,9 +626,9 @@ private fun PathNavigationBar(
                 itemsIndexed(pathNames) { index, name ->
                     val isLast = index == pathNames.lastIndex
 
-                    Text(
+                    AppText(
                         text = name,
-                        style = MaterialTheme.typography.labelSmall,
+                        style = LegadoTheme.typography.labelSmall,
                         fontWeight = if (isLast) FontWeight.SemiBold else FontWeight.Medium,
                         color = if (isLast)
                             MaterialTheme.colorScheme.primary
@@ -716,9 +717,9 @@ private fun RemoteBookItem(
                 modifier = Modifier.weight(1f)
             ) {
 
-                Text(
+                AppText(
                     text = book.filename.substringBeforeLast("."),
-                    style = MaterialTheme.typography.bodyMedium,
+                    style = LegadoTheme.typography.bodyMedium,
                     maxLines = 1,
                     overflow = TextOverflow.Ellipsis
                 )
@@ -732,7 +733,7 @@ private fun RemoteBookItem(
                         if (book.contentType.isNotEmpty()) {
                             TextCard(
                                 text = book.contentType.uppercase(),
-                                textStyle = MaterialTheme.typography.labelSmall,
+                                textStyle = LegadoTheme.typography.labelSmall,
                                 horizontalPadding = 4.dp,
                                 verticalPadding = 2.dp,
                                 cornerRadius = 4.dp,
@@ -743,11 +744,11 @@ private fun RemoteBookItem(
                             Spacer(modifier = Modifier.width(6.dp))
                         }
 
-                        Text(
+                        AppText(
                             text = "${ConvertUtils.formatFileSize(book.size)} • ${
                                 AppConst.dateFormat.format(book.lastModify)
                             }",
-                            style = MaterialTheme.typography.labelMedium,
+                            style = LegadoTheme.typography.labelMedium,
                             color = MaterialTheme.colorScheme.onSurfaceVariant
                         )
                     }

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

@@ -30,7 +30,6 @@ import androidx.compose.material3.ExposedDropdownMenuDefaults
 import androidx.compose.material3.Icon
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
@@ -47,12 +46,13 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import io.legado.app.R
 import io.legado.app.ui.book.changecover.ChangeCoverDialog
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.button.TopBarButtonVariant
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.cover.Cover
 import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.utils.SelectImageContract
 import io.legado.app.utils.launch
 import io.legado.app.utils.showDialogFragment
@@ -71,7 +71,7 @@ fun BookInfoEditScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = { Text(text = stringResource(id = R.string.book_info_edit)) },
+                title = stringResource(id = R.string.book_info_edit),
                 navigationIcon = {
                     TopbarNavigationButton(
                         onClick = onBack,
@@ -191,35 +191,35 @@ fun BookInfoEditContent(
         OutlinedTextField(
             value = uiState.name,
             onValueChange = { viewModel.onNameChange(it) },
-            label = { Text("书名") },
+            label = { AppText("书名") },
             modifier = Modifier.fillMaxWidth()
         )
         Spacer(modifier = Modifier.height(8.dp))
         OutlinedTextField(
             value = uiState.author,
             onValueChange = { viewModel.onAuthorChange(it) },
-            label = { Text("作者") },
+            label = { AppText("作者") },
             modifier = Modifier.fillMaxWidth()
         )
         Spacer(modifier = Modifier.height(8.dp))
         OutlinedTextField(
             value = uiState.coverUrl ?: "",
             onValueChange = { viewModel.onCoverUrlChange(it) },
-            label = { Text("封面链接") },
+            label = { AppText("封面链接") },
             modifier = Modifier.fillMaxWidth()
         )
         Spacer(modifier = Modifier.height(8.dp))
         OutlinedTextField(
             value = uiState.intro ?: "",
             onValueChange = { viewModel.onIntroChange(it) },
-            label = { Text("简介") },
+            label = { AppText("简介") },
             modifier = Modifier.fillMaxWidth()
         )
         Spacer(modifier = Modifier.height(8.dp))
         OutlinedTextField(
             value = uiState.remark ?: "",
             onValueChange = { viewModel.onRemarkChange(it) },
-            label = { Text("备注") },
+            label = { AppText("备注") },
             modifier = Modifier.fillMaxWidth()
         )
     }
@@ -251,7 +251,7 @@ fun BookTypeDropdown(
             state = textFieldState,
             readOnly = true,
             lineLimits = TextFieldLineLimits.SingleLine,
-            label = { Text("书籍类型") },
+            label = { AppText("书籍类型") },
             trailingIcon = {
                 ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
             },
@@ -269,7 +269,7 @@ fun BookTypeDropdown(
         ) {
             bookTypes.forEach { option ->
                 DropdownMenuItem(
-                    text = { Text(option) },
+                    text = { AppText(option) },
                     onClick = {
                         onTypeSelected(option)
                         expanded = false

+ 50 - 53
app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt

@@ -43,7 +43,6 @@ import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.SnackbarHost
 import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -78,11 +77,10 @@ import androidx.compose.ui.zIndex
 import cn.hutool.core.date.DateUtil
 import io.legado.app.data.entities.readRecord.ReadRecord
 import io.legado.app.data.entities.readRecord.ReadRecordDetail
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.AnimatedTextLine
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.EmptyMessageView
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SearchBarSection
 import io.legado.app.ui.widget.components.SectionHeader
 import io.legado.app.ui.widget.components.button.AlertButton
@@ -101,6 +99,9 @@ import io.legado.app.ui.widget.components.heatmap.rememberWeeks
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
 import io.legado.app.ui.widget.components.swipe.SwipeAction
 import io.legado.app.ui.widget.components.swipe.SwipeActionContainer
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.utils.StringUtils.formatFriendlyDate
 import kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
@@ -148,11 +149,7 @@ fun ReadRecordScreen(
         topBar = {
             Column {
                 GlassMediumFlexibleTopAppBar(
-                    title = {
-                        Text(
-                            text = "阅读记录"
-                        )
-                    },
+                    title = "阅读记录",
                     subtitle = {
                         val subTitle = when (displayMode) {
                             DisplayMode.AGGREGATE -> "汇总视图"
@@ -271,10 +268,10 @@ fun ReadRecordScreen(
             onDismissRequest = {
                 pendingDeleteAction = null
             },
-            title = { Text("确认删除") },
+            title = { AppText("确认删除") },
             text = {
                 Column {
-                    Text("确定要删除这条记录吗?")
+                    AppText("确定要删除这条记录吗?")
                     Spacer(modifier = Modifier.height(8.dp))
                     Row(
                         modifier = Modifier
@@ -289,10 +286,10 @@ fun ReadRecordScreen(
                         verticalAlignment = Alignment.CenterVertically
                     ) {
                         Checkbox(checked = skipDeleteConfirmTemp, onCheckedChange = null)
-                        Text(
+                        AppText(
                             text = "不再提示",
                             modifier = Modifier.padding(start = 8.dp),
-                            style = MaterialTheme.typography.bodyMedium
+                            style = LegadoTheme.typography.bodyMedium
                         )
                     }
                 }
@@ -311,7 +308,7 @@ fun ReadRecordScreen(
                 TextButton(onClick = {
                     pendingDeleteAction = null
                 }) {
-                    Text("取消")
+                    AppText("取消")
                 }
             }
         )
@@ -346,10 +343,10 @@ fun ReadRecordScreen(
 
         AlertDialog(
             onDismissRequest = { mergeDialogData = null },
-            title = { Text("合并阅读记录") },
+            title = { AppText("合并阅读记录") },
             text = {
                 Column {
-                    Text("将以下作者的“${targetRecord.bookName}”合并到 ${targetRecord.bookAuthor.ifBlank { "未知作者" }}")
+                    AppText("将以下作者的“${targetRecord.bookName}”合并到 ${targetRecord.bookAuthor.ifBlank { "未知作者" }}")
                     Spacer(modifier = Modifier.height(8.dp))
 
                     candidates.forEach { candidate ->
@@ -367,10 +364,10 @@ fun ReadRecordScreen(
                             verticalAlignment = Alignment.CenterVertically
                         ) {
                             Checkbox(checked = isChecked, onCheckedChange = null)
-                            Text(
+                            AppText(
                                 text = "$author(${formatDuring(candidate.readTime)})",
                                 modifier = Modifier.padding(start = 8.dp),
-                                style = MaterialTheme.typography.bodyMedium
+                                style = LegadoTheme.typography.bodyMedium
                             )
                         }
                     }
@@ -386,12 +383,12 @@ fun ReadRecordScreen(
                         mergeDialogData = null
                     }
                 ) {
-                    Text("合并")
+                    AppText("合并")
                 }
             },
             dismissButton = {
                 TextButton(onClick = { mergeDialogData = null }) {
-                    Text("取消")
+                    AppText("取消")
                 }
             }
         )
@@ -686,21 +683,21 @@ fun LatestReadItem(
         Spacer(modifier = Modifier.width(16.dp))
 
         Column(modifier = Modifier.weight(1f)) {
-            Text(
+            AppText(
                 text = record.bookName,
-                style = MaterialTheme.typography.titleMedium,
+                style = LegadoTheme.typography.titleMedium,
                 maxLines = 1,
                 overflow = TextOverflow.Ellipsis
             )
-            Text(
+            AppText(
                 text = record.bookAuthor.ifBlank { "未知作者" },
-                style = MaterialTheme.typography.bodySmall,
+                style = LegadoTheme.typography.bodySmall,
                 color = MaterialTheme.colorScheme.outline,
                 maxLines = 1,
                 overflow = TextOverflow.Ellipsis
             )
             Spacer(modifier = Modifier.height(8.dp))
-            Text(
+            AppText(
                 modifier = Modifier
                     .basicMarquee(
                         iterations = Int.MAX_VALUE,
@@ -716,7 +713,7 @@ fun LatestReadItem(
                         append("${DateUtil.format(Date(record.lastRead), "yyyy-MM-dd HH:mm")}")
                     }
                 },
-                style = MaterialTheme.typography.labelSmall,
+                style = LegadoTheme.typography.labelSmall,
                 maxLines = 1,
                 overflow = TextOverflow.Ellipsis
             )
@@ -783,9 +780,9 @@ fun TimelineSessionItem(
                 modifier = Modifier.width(48.dp),
                 verticalArrangement = Arrangement.Center
             ) {
-                Text(
+                AppText(
                     text = endTimeText,
-                    style = MaterialTheme.typography.bodySmall
+                    style = LegadoTheme.typography.bodySmall
                 )
             }
 
@@ -795,23 +792,23 @@ fun TimelineSessionItem(
                 Cover(coverPath)
                 Spacer(modifier = Modifier.width(8.dp))
                 Column {
-                    Text(
+                    AppText(
                         text = session.bookName,
-                        style = MaterialTheme.typography.titleMedium,
+                        style = LegadoTheme.typography.titleMedium,
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
                     )
-                    Text(
+                    AppText(
                         text = session.bookAuthor.ifBlank { "未知作者" },
-                        style = MaterialTheme.typography.bodySmall,
+                        style = LegadoTheme.typography.bodySmall,
                         color = MaterialTheme.colorScheme.outline,
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
                     )
                     Spacer(modifier = Modifier.height(8.dp))
-                    Text(
+                    AppText(
                         text = chapterTitle.orEmpty(),
-                        style = MaterialTheme.typography.labelSmall,
+                        style = LegadoTheme.typography.labelSmall,
                         color = MaterialTheme.colorScheme.outline,
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
@@ -847,21 +844,21 @@ fun ReadRecordItem(
         Spacer(modifier = Modifier.width(16.dp))
 
         Column(modifier = Modifier.weight(1f)) {
-            Text(
+            AppText(
                 text = detail.bookName,
-                style = MaterialTheme.typography.titleMedium,
+                style = LegadoTheme.typography.titleMedium,
                 maxLines = 1
             )
-            Text(
+            AppText(
                 text = detail.bookAuthor.ifBlank { "未知作者" },
-                style = MaterialTheme.typography.bodySmall,
+                style = LegadoTheme.typography.bodySmall,
                 color = MaterialTheme.colorScheme.outline,
             )
             Spacer(modifier = Modifier.height(8.dp))
-            Text(
+            AppText(
                 text = "阅读时长: ${formatDuring(detail.readTime)}",
                 color = MaterialTheme.colorScheme.outline,
-                style = MaterialTheme.typography.labelSmall
+                style = LegadoTheme.typography.labelSmall
             )
         }
     }
@@ -876,17 +873,17 @@ fun DateHeader(
     SectionHeader(
         titleContent = {
             Column {
-                Text(
+                AppText(
                     text = dateText,
-                    style = MaterialTheme.typography.bodyMedium,
+                    style = LegadoTheme.typography.bodyMedium,
                     fontWeight = FontWeight.Bold,
                     color = MaterialTheme.colorScheme.secondary
                 )
 
                 dailyTotalTime?.let { total ->
-                    Text(
+                    AppText(
                         text = "已读 ${formatDuring(total)}",
-                        style = MaterialTheme.typography.bodySmall,
+                        style = LegadoTheme.typography.bodySmall,
                         color = MaterialTheme.colorScheme.onSurface
                     )
                 }
@@ -934,28 +931,28 @@ fun ReadingSummaryCard(
 
             Column(modifier = Modifier.weight(1f)) {
 
-                Text(
+                AppText(
                     text = title,
-                    style = MaterialTheme.typography.labelLarge,
+                    style = LegadoTheme.typography.labelLarge,
                     color = MaterialTheme.colorScheme.primary
                 )
 
                 Spacer(modifier = Modifier.height(4.dp))
 
                 Row(verticalAlignment = Alignment.Bottom) {
-                    Text(
+                    AppText(
                         text = "已读 ",
-                        style = MaterialTheme.typography.titleMedium
+                        style = LegadoTheme.typography.titleMedium
                     )
-                    Text(
+                    AppText(
                         text = "$bookCount",
-                        style = MaterialTheme.typography.headlineMedium,
+                        style = LegadoTheme.typography.headlineMedium,
                         color = MaterialTheme.colorScheme.primary,
                         fontWeight = FontWeight.Bold,
                     )
-                    Text(
+                    AppText(
                         text = " 本书",
-                        style = MaterialTheme.typography.titleMedium
+                        style = LegadoTheme.typography.titleMedium
                     )
                 }
 
@@ -965,9 +962,9 @@ fun ReadingSummaryCard(
                 val minutes = totalDurationMinutes % 60
                 val timeString = if (hours > 0) "${hours}小时${minutes}分钟" else "${minutes}分钟"
 
-                Text(
+                AppText(
                     text = "共阅读 $timeString",
-                    style = MaterialTheme.typography.bodySmall,
+                    style = LegadoTheme.typography.bodySmall,
                     color = MaterialTheme.colorScheme.onSurfaceVariant
                 )
             }

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

@@ -44,7 +44,6 @@ import androidx.compose.material3.ListItem
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.PlainTooltip
-import androidx.compose.material3.Text
 import androidx.compose.material3.TooltipAnchorPosition
 import androidx.compose.material3.TooltipBox
 import androidx.compose.material3.TooltipDefaults
@@ -64,11 +63,9 @@ import androidx.compose.ui.text.buildAnnotatedString
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import io.legado.app.data.entities.SearchContentHistory
-import io.legado.app.ui.widget.components.AnimatedText
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.EmptyMessageView
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SearchBarSection
 import io.legado.app.ui.widget.components.button.SmallAnimatedActionButton
 import io.legado.app.ui.widget.components.button.SmallIconButton
@@ -76,6 +73,9 @@ import io.legado.app.ui.widget.components.button.TopBarAnimatedActionButton
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
+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 kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
 
@@ -140,12 +140,9 @@ fun SearchContentScreen(
         topBar = {
             Column {
                 GlassMediumFlexibleTopAppBar(
-                    title = {
-                        val title = if (searchQuery.isNotBlank() && searchResults.isNotEmpty()) {
-                            "共 ${searchResults.size} 条结果"
-                        } else "搜索内容"
-                        AnimatedText(text = title)
-                    },
+                    title = if (searchQuery.isNotBlank() && searchResults.isNotEmpty()) {
+                        "共 ${searchResults.size} 条结果"
+                    } else "搜索内容",
                     navigationIcon = { TopbarNavigationButton(onClick = onBack) },
                     actions = {
                         Row(
@@ -191,7 +188,7 @@ fun SearchContentScreen(
                 ),
                 tooltip = {
                     PlainTooltip {
-                        Text(if (isSearching) "停止搜索" else "跳转到当前章节")
+                        AppText(if (isSearching) "停止搜索" else "跳转到当前章节")
                     }
                 },
                 state = rememberTooltipState(),
@@ -310,9 +307,9 @@ fun SearchHistoryList(
                 .fillMaxWidth()
                 .padding(horizontal = 16.dp, vertical = 8.dp)
         ) {
-            Text(
+            AppText(
                 text = "搜索历史",
-                style = MaterialTheme.typography.titleSmallEmphasized,
+                style = LegadoTheme.typography.titleSmallEmphasized,
                 color = MaterialTheme.colorScheme.primary,
                 modifier = Modifier.align(Alignment.Center)
             )
@@ -342,7 +339,7 @@ fun SearchHistoryList(
                             .clickable { onHistoryClick(item) }
                             .animateItem(),
                         headlineContent = {
-                            Text(
+                            AppText(
                                 text = item.query,
                                 maxLines = 1,
                                 overflow = TextOverflow.Ellipsis
@@ -378,7 +375,7 @@ fun SearchHistoryList(
                                 modifier = Modifier.size(18.dp)
                             )
                             Spacer(Modifier.width(8.dp))
-                            Text("清除搜索历史")
+                            AppText("清除搜索历史")
                         }
                     }
                 }
@@ -407,7 +404,7 @@ fun SearchResultItem(
         Box(modifier = Modifier.padding(16.dp)) {
 
             Column {
-                Text(
+                AppText(
                     text = buildAnnotatedString {
                         append(
                             result.getTitleSpannable(
@@ -415,14 +412,14 @@ fun SearchResultItem(
                             )
                         )
                     },
-                    style = MaterialTheme.typography.titleSmall
+                    style = LegadoTheme.typography.titleSmall
                 )
 
                 Spacer(modifier = Modifier.height(8.dp))
                 HorizontalDivider()
                 Spacer(modifier = Modifier.height(8.dp))
 
-                Text(
+                AppText(
                     text = buildAnnotatedString {
                         append(
                             result.getContentSpannable(
@@ -432,7 +429,7 @@ fun SearchResultItem(
                             )
                         )
                     },
-                    style = MaterialTheme.typography.bodyMedium
+                    style = LegadoTheme.typography.bodyMedium
                 )
             }
 

+ 24 - 23
app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt

@@ -63,7 +63,6 @@ import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.PrimaryScrollableTabRow
 import androidx.compose.material3.Surface
 import androidx.compose.material3.Tab
-import androidx.compose.material3.Text
 import androidx.compose.material3.ToggleFloatingActionButton
 import androidx.compose.material3.ToggleFloatingActionButtonDefaults.animateIcon
 import androidx.compose.material3.animateFloatingActionButton
@@ -95,11 +94,11 @@ import io.legado.app.data.entities.Bookmark
 import io.legado.app.help.book.isLocal
 import io.legado.app.ui.book.toc.rule.TxtTocRuleActivity
 import io.legado.app.ui.replace.ReplaceEditRoute
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.CollapsibleHeader
 import io.legado.app.ui.widget.components.ActionItem
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.EmptyMessageView
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SelectionBottomBar
 import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet
 import io.legado.app.ui.widget.components.bookmark.BookmarkItem
@@ -109,7 +108,9 @@ import io.legado.app.ui.widget.components.divider.PillHeaderDivider
 import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.topbar.DynamicTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
@@ -312,33 +313,33 @@ fun TocScreen(
                     when (pagerState.currentPage) {
                         0 -> {
                             RoundDropdownMenuItem(
-                                text = { Text("使用替换规则") },
+                                text = { AppText("使用替换规则") },
                                 trailingIcon = {
                                     Checkbox(checked = useReplace, onCheckedChange = null)
                                 },
                                 onClick = { viewModel.toggleUseReplace() }
                             )
                             RoundDropdownMenuItem(
-                                text = { Text("显示字数") },
+                                text = { AppText("显示字数") },
                                 trailingIcon = {
                                     Checkbox(checked = showWordCount, onCheckedChange = null)
                                 },
                                 onClick = { viewModel.toggleShowWordCount() }
                             )
                             RoundDropdownMenuItem(
-                                text = { Text("反转目录") },
+                                text = { AppText("反转目录") },
                                 onClick = { viewModel.reverseToc() }
                             )
                             PillDivider()
                             RoundDropdownMenuItem(
-                                text = { Text("替换规则") },
+                                text = { AppText("替换规则") },
                                 onClick = {
                                     onOpenReplaceRule(null)
                                     dismiss()
                                 }
                             )
                             RoundDropdownMenuItem(
-                                text = { Text("新建替换规则") },
+                                text = { AppText("新建替换规则") },
                                 onClick = {
                                     val scopes = mutableListOf<String>()
                                     book?.name?.let { scopes.add(it) }
@@ -358,7 +359,7 @@ fun TocScreen(
                             if (book?.isLocal == true) {
                                 PillHeaderDivider(title = "本地书籍选项")
                                 RoundDropdownMenuItem(
-                                    text = { Text("本地书籍目录规则") },
+                                    text = { AppText("本地书籍目录规则") },
                                     onClick = {
                                         val intent =
                                             Intent(context, TxtTocRuleActivity::class.java).apply {
@@ -369,7 +370,7 @@ fun TocScreen(
                                     }
                                 )
                                 RoundDropdownMenuItem(
-                                    text = { Text("拆分超长章节") },
+                                    text = { AppText("拆分超长章节") },
                                     trailingIcon = {
                                         Checkbox(
                                             checked = viewModel.isSplitLongChapter,
@@ -386,7 +387,7 @@ fun TocScreen(
 
                         else -> {
                             RoundDropdownMenuItem(
-                                text = { Text("导出书签为JSON") },
+                                text = { AppText("导出书签为JSON") },
                                 onClick = {
                                     val dateFormat = SimpleDateFormat(
                                         "yyyyMMdd_HHmm",
@@ -398,7 +399,7 @@ fun TocScreen(
                                 }
                             )
                             RoundDropdownMenuItem(
-                                text = { Text("导出书签为MarkDown") },
+                                text = { AppText("导出书签为MarkDown") },
                                 onClick = {
                                     val dateFormat = SimpleDateFormat(
                                         "yyyyMMdd_HHmm",
@@ -428,7 +429,7 @@ fun TocScreen(
                                 selected = pagerState.currentPage == 0,
                                 onClick = { scope.launch { pagerState.animateScrollToPage(0) } },
                                 text = {
-                                    Text(
+                                    AppText(
                                         text = "目录",
                                         modifier = Modifier.padding(horizontal = 16.dp),
                                         color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -439,7 +440,7 @@ fun TocScreen(
                                 selected = pagerState.currentPage == 1,
                                 onClick = { scope.launch { pagerState.animateScrollToPage(1) } },
                                 text = {
-                                    Text(
+                                    AppText(
                                         text = "书签",
                                         modifier = Modifier.padding(horizontal = 16.dp),
                                         color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -464,13 +465,13 @@ fun TocScreen(
                                     onDismissRequest = { showVolumeMenu = false }
                                 ) {
                                     RoundDropdownMenuItem(
-                                        text = { Text("展开所有卷") },
+                                        text = { AppText("展开所有卷") },
                                         onClick = {
                                             viewModel.expandAllVolumes(); showVolumeMenu = false
                                         }
                                     )
                                     RoundDropdownMenuItem(
-                                        text = { Text("收起所有卷") },
+                                        text = { AppText("收起所有卷") },
                                         onClick = {
                                             viewModel.collapseAllVolumes(); showVolumeMenu = false
                                         }
@@ -482,7 +483,7 @@ fun TocScreen(
                                         PillHeaderDivider(title = "快速跳转")
                                         volumeItems.forEach { uiItem ->
                                             RoundDropdownMenuItem(
-                                                text = { Text(uiItem.title) },
+                                                text = { AppText(uiItem.title) },
                                                 onClick = {
                                                     scope.launch {
                                                         val targetIndex =
@@ -541,7 +542,7 @@ fun TocScreen(
                             fabMenuExpanded = false
                         },
                         icon = { Icon(icon, contentDescription = null) },
-                        text = { Text(text = label) }
+                        text = { AppText(text = label) }
                     )
                 }
             }
@@ -729,9 +730,9 @@ fun ChapterItem(
                         )
                     }
 
-                    Text(
+                    AppText(
                         text = item.title,
-                        style = MaterialTheme.typography.bodyMediumEmphasized.copy(fontWeight = FontWeight.Medium),
+                        style = LegadoTheme.typography.bodyMediumEmphasized.copy(fontWeight = FontWeight.Medium),
                         color = textColor,
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
@@ -739,9 +740,9 @@ fun ChapterItem(
                 }
 
                 if (!item.tag.isNullOrEmpty()) {
-                    Text(
+                    AppText(
                         text = item.tag,
-                        style = MaterialTheme.typography.labelSmallEmphasized,
+                        style = LegadoTheme.typography.labelSmallEmphasized,
                         color = detailColor.copy(alpha = 0.8f),
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
@@ -910,11 +911,11 @@ private fun StatusIcon(
                     color = Color.Transparent
                 ) {
                     if (wordCount != null) {
-                        Text(
+                        AppText(
                             modifier = Modifier
                                 .padding(horizontal = 8.dp, vertical = 4.dp),
                             text = wordCount,
-                            style = MaterialTheme.typography.labelSmall.copy(fontSize = 9.sp),
+                            style = LegadoTheme.typography.labelSmall.copy(fontSize = 9.sp),
                             color = MaterialTheme.colorScheme.onSurfaceVariant
                         )
                     }

+ 9 - 9
app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt

@@ -19,11 +19,9 @@ import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.SnackbarResult
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.rememberModalBottomSheetState
 import androidx.compose.runtime.Composable
@@ -46,6 +44,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import io.legado.app.R
 import io.legado.app.base.BaseRuleEvent
 import io.legado.app.data.entities.TxtTocRule
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.ActionItem
 import io.legado.app.ui.widget.components.DraggableSelectionHandler
 import io.legado.app.ui.widget.components.button.SmallIconButton
@@ -59,6 +58,7 @@ import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.rules.RuleEditFields
 import io.legado.app.ui.widget.components.rules.RuleEditSheet
 import io.legado.app.ui.widget.components.rules.RuleListScaffold
+import io.legado.app.ui.widget.components.text.AppText
 import org.koin.androidx.compose.koinViewModel
 import sh.calvin.reorderable.rememberReorderableLazyListState
 
@@ -196,8 +196,8 @@ fun TxtRuleScreen(
             onConfirm = { viewModel.saveImportedRules() },
             itemContent = { rule, _ ->
                 Column {
-                    Text(rule.name, style = MaterialTheme.typography.titleMedium)
-                    Text(rule.rule, style = MaterialTheme.typography.bodySmall, maxLines = 1)
+                    AppText(rule.name, style = LegadoTheme.typography.titleMedium)
+                    AppText(rule.rule, style = LegadoTheme.typography.bodySmall, maxLines = 1)
                 }
             }
         )
@@ -212,16 +212,16 @@ fun TxtRuleScreen(
     showDeleteRuleDialog?.let { rule ->
         AlertDialog(
             onDismissRequest = { showDeleteRuleDialog = null },
-            title = { Text(stringResource(R.string.delete)) },
-            text = { Text(stringResource(R.string.del_msg)) },
+            title = { AppText(stringResource(R.string.delete)) },
+            text = { AppText(stringResource(R.string.del_msg)) },
             confirmButton = {
                 OutlinedButton(onClick = {
                     viewModel.delete(rule); showDeleteRuleDialog = null
-                }) { Text(stringResource(R.string.ok)) }
+                }) { AppText(stringResource(R.string.ok)) }
             },
             dismissButton = {
                 TextButton(onClick = { showDeleteRuleDialog = null }) {
-                    Text(
+                    AppText(
                         stringResource(R.string.cancel)
                     )
                 }
@@ -312,7 +312,7 @@ fun TxtRuleScreen(
         snackbarHostState = snackbarHostState,
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.import_str)) },
+                text = { AppText(stringResource(R.string.import_str)) },
                 onClick = { showImportSheet = true; dismiss() },
                 leadingIcon = { Icon(Icons.Default.FileOpen, null) }
             )

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

@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -14,11 +13,11 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -36,7 +35,7 @@ fun ConfigNavScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = { Text(stringResource(R.string.setting)) },
+                title = stringResource(R.string.setting),
                 scrollBehavior = scrollBehavior,
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBackClick)

+ 21 - 23
app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt

@@ -19,7 +19,6 @@ import androidx.compose.material3.IconButton
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.SnackbarHost
 import androidx.compose.material3.SnackbarHostState
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TextField
 import androidx.compose.runtime.Composable
@@ -42,14 +41,15 @@ import io.legado.app.help.storage.Restore
 import io.legado.app.lib.permission.Permissions
 import io.legado.app.lib.permission.PermissionsCompat
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
 import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
 import io.legado.app.ui.widget.components.settingItem.InputSettingItem
 import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.utils.isContentScheme
 import io.legado.app.utils.takePersistablePermissionSafely
 import kotlinx.coroutines.launch
@@ -166,9 +166,7 @@ fun BackupConfigScreen(
         },
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = {
-                    Text(stringResource(R.string.backup_restore))
-                },
+                title = stringResource(R.string.backup_restore),
                 scrollBehavior = scrollBehavior,
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBackClick)
@@ -387,19 +385,19 @@ fun BackupConfigScreen(
     if (showWebDavAuthDialog) {
         AlertDialog(
             onDismissRequest = { showWebDavAuthDialog = false },
-            title = { Text(stringResource(R.string.web_dav_account)) },
+            title = { AppText(stringResource(R.string.web_dav_account)) },
             text = {
                 Column {
                     TextField(
                         value = tempAccount,
                         onValueChange = { tempAccount = it },
-                        label = { Text("账号") }
+                        label = { AppText("账号") }
                     )
                     Spacer(modifier = Modifier.padding(8.dp))
                     TextField(
                         value = tempPassword,
                         onValueChange = { tempPassword = it },
-                        label = { Text("密码") },
+                        label = { AppText("密码") },
                         visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
                         keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
                         trailingIcon = {
@@ -432,12 +430,12 @@ fun BackupConfigScreen(
                         }
                     }
                 }) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             },
             dismissButton = {
                 TextButton(onClick = { showWebDavAuthDialog = false }) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
             }
         )
@@ -484,7 +482,7 @@ fun BackupConfigScreen(
     if (showRestoreSheet && backupNames.isNotEmpty()) {
         AlertDialog(
             onDismissRequest = { showRestoreSheet = false },
-            title = { Text(stringResource(R.string.select_restore_file)) },
+            title = { AppText(stringResource(R.string.select_restore_file)) },
             text = {
                 Column {
                     backupNames.forEach { name ->
@@ -508,7 +506,7 @@ fun BackupConfigScreen(
                                 }
                             )
                         }) {
-                            Text(name)
+                            AppText(name)
                         }
                     }
                 }
@@ -516,7 +514,7 @@ fun BackupConfigScreen(
             confirmButton = {},
             dismissButton = {
                 TextButton(onClick = { showRestoreSheet = false }) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
             }
         )
@@ -535,7 +533,7 @@ fun BackupConfigScreen(
                 io.legado.app.help.storage.BackupConfig.saveIgnoreConfig()
                 showBackupIgnoreDialog = false
             },
-            title = { Text(stringResource(R.string.restore_ignore)) },
+            title = { AppText(stringResource(R.string.restore_ignore)) },
             text = {
                 Column {
                     io.legado.app.help.storage.BackupConfig.ignoreTitle.forEachIndexed { index, title ->
@@ -546,7 +544,7 @@ fun BackupConfigScreen(
                             ] = checkedItems[index]
                         }) {
                             val isChecked = checkedItems[index]
-                            Text(if (isChecked) "✓ $title" else title)
+                            AppText(if (isChecked) "✓ $title" else title)
                         }
                     }
                 }
@@ -556,7 +554,7 @@ fun BackupConfigScreen(
                     io.legado.app.help.storage.BackupConfig.saveIgnoreConfig()
                     showBackupIgnoreDialog = false
                 }) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             },
             dismissButton = {
@@ -564,7 +562,7 @@ fun BackupConfigScreen(
                     io.legado.app.help.storage.BackupConfig.saveIgnoreConfig()
                     showBackupIgnoreDialog = false
                 }) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
             }
         )
@@ -573,7 +571,7 @@ fun BackupConfigScreen(
     if (showLoadingDialog) {
         AlertDialog(
             onDismissRequest = {},
-            title = { Text(loadingText) },
+            title = { AppText(loadingText) },
             confirmButton = {},
             dismissButton = {}
         )
@@ -589,16 +587,16 @@ fun ConfirmDialog(
 ) {
     AlertDialog(
         onDismissRequest = onDismiss,
-        title = { Text(title) },
-        text = { Text(text) },
+        title = { AppText(title) },
+        text = { AppText(text) },
         confirmButton = {
             OutlinedButton(onClick = onConfirm) {
-                Text(stringResource(R.string.ok))
+                AppText(stringResource(R.string.ok))
             }
         },
         dismissButton = {
             TextButton(onClick = onDismiss) {
-                Text(stringResource(R.string.cancel))
+                AppText(stringResource(R.string.cancel))
             }
         }
     )

+ 3 - 4
app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt

@@ -12,7 +12,6 @@ import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -27,14 +26,14 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.constant.PreferKey
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
 import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
 import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
 import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import org.koin.androidx.compose.koinViewModel
 
 @OptIn(ExperimentalMaterial3Api::class)
@@ -52,7 +51,7 @@ fun CoverConfigScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = { Text(stringResource(R.string.cover_config)) },
+                title = stringResource(R.string.cover_config),
                 scrollBehavior = scrollBehavior,
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBackClick)

+ 4 - 3
app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt

@@ -22,7 +22,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -36,8 +35,10 @@ import androidx.compose.ui.unit.dp
 import coil.compose.AsyncImage
 import io.legado.app.R
 import io.legado.app.constant.PreferKey
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -69,9 +70,9 @@ fun CoverManageSheet(
                 .fillMaxWidth()
                 .padding(bottom = 24.dp)
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.default_cover),
-                style = MaterialTheme.typography.titleMedium,
+                style = LegadoTheme.typography.titleMedium,
                 modifier = Modifier.padding(16.dp)
             )
 

+ 11 - 7
app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt

@@ -11,7 +11,6 @@ import androidx.compose.material3.Checkbox
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -25,8 +24,10 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.model.BookCover
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.InputSettingItem
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.toastOnUi
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
@@ -58,9 +59,9 @@ fun CoverRuleConfigSheet(
                 .fillMaxWidth()
                 .padding(16.dp)
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.cover_rule),
-                style = MaterialTheme.typography.titleLarge,
+                style = LegadoTheme.typography.titleLarge,
                 modifier = Modifier.padding(bottom = 16.dp)
             )
 
@@ -72,7 +73,7 @@ fun CoverRuleConfigSheet(
                     checked = enable,
                     onCheckedChange = { enable = it }
                 )
-                Text(text = stringResource(R.string.enable))
+                AppText(text = stringResource(R.string.enable))
             }
 
             InputSettingItem(
@@ -97,13 +98,16 @@ fun CoverRuleConfigSheet(
                     BookCover.delCoverRule()
                     onDismissRequest()
                 }) {
-                    Text(stringResource(R.string.delete), color = MaterialTheme.colorScheme.error)
+                    AppText(
+                        stringResource(R.string.delete),
+                        color = MaterialTheme.colorScheme.error
+                    )
                 }
 
                 Spacer(modifier = Modifier.weight(1f))
 
                 OutlinedButton(onClick = onDismissRequest) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
 
                 Spacer(modifier = Modifier.padding(horizontal = 4.dp))
@@ -118,7 +122,7 @@ fun CoverRuleConfigSheet(
                         onDismissRequest()
                     }
                 }) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             }
         }

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

@@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.material3.Button
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
+import io.legado.app.ui.widget.components.text.AppText
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
@@ -18,6 +18,7 @@ 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.theme.LegadoTheme
 import io.legado.app.ui.widget.components.checkBox.CheckboxGroupContainer
 import io.legado.app.ui.widget.components.checkBox.CheckboxItem
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
@@ -41,9 +42,9 @@ fun CheckSourceBottomSheet(
                 .padding(horizontal = 16.dp)
                 .padding(bottom = 32.dp)
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.check_source_config),
-                style = MaterialTheme.typography.titleLarge,
+                style = LegadoTheme.typography.titleLarge,
                 modifier = Modifier.padding(vertical = 16.dp)
             )
 
@@ -131,7 +132,7 @@ fun CheckSourceBottomSheet(
                 horizontalArrangement = Arrangement.End
             ) {
                 TextButton(onClick = onDismiss) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
                 Button(onClick = {
                     if (viewModel.saveCheckSourceConfig()) {
@@ -140,7 +141,7 @@ fun CheckSourceBottomSheet(
                         Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show()
                     }
                 }) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             }
         }

+ 17 - 16
app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt

@@ -24,7 +24,6 @@ import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
@@ -41,8 +40,10 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.help.DirectLinkUpload
 import io.legado.app.lib.dialogs.selector
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.checkBox.CheckboxItem
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.GSON
 import io.legado.app.utils.fromJsonObject
 import io.legado.app.utils.getClipText
@@ -75,9 +76,9 @@ fun DirectLinkUploadBottomSheet(
         ) {
             CenterAlignedTopAppBar(
                 title = {
-                    Text(
+                    AppText(
                         text = stringResource(R.string.direct_link_upload_config),
-                        style = MaterialTheme.typography.titleLarge
+                        style = LegadoTheme.typography.titleLarge
                     )
                 },
                 actions = {
@@ -89,7 +90,7 @@ fun DirectLinkUploadBottomSheet(
                         onDismissRequest = { showMenu = false }
                     ) {
                         DropdownMenuItem(
-                            text = { Text("导入默认") },
+                            text = { AppText("导入默认") },
                             leadingIcon = { Icon(Icons.Default.Download, null) },
                             onClick = {
                                 showMenu = false
@@ -99,7 +100,7 @@ fun DirectLinkUploadBottomSheet(
                             }
                         )
                         DropdownMenuItem(
-                            text = { Text(stringResource(R.string.copy_rule)) },
+                            text = { AppText(stringResource(R.string.copy_rule)) },
                             leadingIcon = { Icon(Icons.Default.ContentCopy, null) },
                             onClick = {
                                 showMenu = false
@@ -113,7 +114,7 @@ fun DirectLinkUploadBottomSheet(
                             }
                         )
                         DropdownMenuItem(
-                            text = { Text(stringResource(R.string.paste_rule)) },
+                            text = { AppText(stringResource(R.string.paste_rule)) },
                             leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
                             onClick = {
                                 showMenu = false
@@ -141,7 +142,7 @@ fun DirectLinkUploadBottomSheet(
             OutlinedTextField(
                 value = viewModel.uploadUrl,
                 onValueChange = { viewModel.uploadUrl = it },
-                label = { Text(stringResource(R.string.upload_url)) },
+                label = { AppText(stringResource(R.string.upload_url)) },
                 modifier = Modifier.fillMaxWidth(),
             )
 
@@ -150,7 +151,7 @@ fun DirectLinkUploadBottomSheet(
             OutlinedTextField(
                 value = viewModel.downloadUrlRule,
                 onValueChange = { viewModel.downloadUrlRule = it },
-                label = { Text(stringResource(R.string.download_url_rule)) },
+                label = { AppText(stringResource(R.string.download_url_rule)) },
                 modifier = Modifier.fillMaxWidth(),
             )
 
@@ -159,7 +160,7 @@ fun DirectLinkUploadBottomSheet(
             OutlinedTextField(
                 value = viewModel.summary,
                 onValueChange = { viewModel.summary = it },
-                label = { Text(stringResource(R.string.summary)) },
+                label = { AppText(stringResource(R.string.summary)) },
                 modifier = Modifier.fillMaxWidth(),
             )
 
@@ -178,11 +179,11 @@ fun DirectLinkUploadBottomSheet(
                 TextButton(onClick = {
                     viewModel.testRule { result -> showTestResult = result }
                 }) {
-                    Text("测试")
+                    AppText("测试")
                 }
                 Spacer(Modifier.weight(1f))
                 OutlinedButton(onClick = onDismiss) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
                 Button(onClick = {
                     if (viewModel.saveDirectLinkRule()) {
@@ -191,7 +192,7 @@ fun DirectLinkUploadBottomSheet(
                         context.toastOnUi("请填写完整信息")
                     }
                 }) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             }
         }
@@ -200,15 +201,15 @@ fun DirectLinkUploadBottomSheet(
     showTestResult?.let { result ->
         AlertDialog(
             onDismissRequest = { showTestResult = null },
-            title = { Text("Result") },
-            text = { Text(result) },
+            title = { AppText("Result") },
+            text = { AppText(result) },
             confirmButton = {
                 TextButton(onClick = {
                     showTestResult = null
-                }) { Text(stringResource(R.string.ok)) }
+                }) { AppText(stringResource(R.string.ok)) }
             },
             dismissButton = {
-                TextButton(onClick = { context.sendToClip(result) }) { Text(stringResource(R.string.copy_text)) }
+                TextButton(onClick = { context.sendToClip(result) }) { AppText(stringResource(R.string.copy_text)) }
             }
         )
     }

+ 24 - 17
app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt

@@ -13,7 +13,6 @@ import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.OutlinedButton
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TextField
 import androidx.compose.runtime.Composable
@@ -30,8 +29,6 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.service.WebService
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
@@ -40,6 +37,9 @@ import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
 import io.legado.app.ui.widget.components.settingItem.InputSettingItem
 import io.legado.app.ui.widget.components.settingItem.SliderSettingItem
 import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.utils.restart
 import io.legado.app.utils.takePersistablePermissionSafely
 import org.koin.androidx.compose.koinViewModel
@@ -83,9 +83,7 @@ fun OtherConfigScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = {
-                    Text(stringResource(R.string.other_setting))
-                },
+                title = stringResource(R.string.other_setting),
                 scrollBehavior = scrollBehavior,
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBackClick)
@@ -200,7 +198,10 @@ fun OtherConfigScreen(
 
                 SliderSettingItem(
                     title = stringResource(R.string.bitmap_cache_size),
-                    description = stringResource(R.string.bitmap_cache_size_summary),
+                    description = stringResource(
+                        R.string.bitmap_cache_size_summary,
+                        OtherConfig.bitmapCacheSize
+                    ),
                     value = OtherConfig.bitmapCacheSize.toFloat(),
                     defaultValue = 32f,
                     valueRange = 1f..2047f,
@@ -211,7 +212,10 @@ fun OtherConfigScreen(
 
                 SliderSettingItem(
                     title = stringResource(R.string.image_retain_number),
-                    description = stringResource(R.string.image_retain_number_summary),
+                    description = stringResource(
+                        R.string.image_retain_number_summary,
+                        OtherConfig.imageRetainNum
+                    ),
                     value = OtherConfig.imageRetainNum.toFloat(),
                     defaultValue = 10f,
                     valueRange = 0f..100f,
@@ -220,7 +224,10 @@ fun OtherConfigScreen(
 
                 SliderSettingItem(
                     title = stringResource(R.string.pre_download),
-                    description = stringResource(R.string.pre_download_s),
+                    description = stringResource(
+                        R.string.pre_download_s,
+                        OtherConfig.preDownloadNum
+                    ),
                     value = OtherConfig.preDownloadNum.toFloat(),
                     defaultValue = 10f,
                     valueRange = 0f..100f,
@@ -458,23 +465,23 @@ fun OtherConfigScreen(
         if (showPasswordDialog) {
             AlertDialog(
                 onDismissRequest = { showPasswordDialog = false },
-                title = { Text(stringResource(R.string.set_local_password)) },
+                title = { AppText(stringResource(R.string.set_local_password)) },
                 text = {
                     TextField(
                         value = tempPassword,
                         onValueChange = { tempPassword = it },
-                        label = { Text("Password") }
+                        label = { AppText("Password") }
                     )
                 },
                 confirmButton = {
                     TextButton(onClick = {
                         viewModel.setLocalPassword(tempPassword)
                         showPasswordDialog = false
-                    }) { Text(stringResource(R.string.ok)) }
+                    }) { AppText(stringResource(R.string.ok)) }
                 },
                 dismissButton = {
                     TextButton(onClick = { showPasswordDialog = false }) {
-                        Text(stringResource(R.string.cancel))
+                        AppText(stringResource(R.string.cancel))
                     }
                 }
             )
@@ -492,16 +499,16 @@ fun ConfirmDialog(
 ) {
     AlertDialog(
         onDismissRequest = onDismiss,
-        title = { Text(title) },
-        text = { Text(text) },
+        title = { AppText(title) },
+        text = { AppText(text) },
         confirmButton = {
             OutlinedButton(onClick = onConfirm) {
-                Text(stringResource(R.string.ok))
+                AppText(stringResource(R.string.ok))
             }
         },
         dismissButton = {
             TextButton(onClick = onDismiss) {
-                Text(stringResource(R.string.cancel))
+                AppText(stringResource(R.string.cancel))
             }
         }
     )

+ 10 - 9
app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt

@@ -11,7 +11,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -23,7 +22,9 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.font.FontWeight
 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.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -40,16 +41,16 @@ fun PageKeySheet(
                 .padding(16.dp),
             verticalArrangement = Arrangement.spacedBy(16.dp)
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.custom_page_key),
-                style = MaterialTheme.typography.titleLarge,
+                style = LegadoTheme.typography.titleLarge,
                 fontWeight = FontWeight.Companion.Bold
             )
 
             OutlinedTextField(
                 value = prevKeys,
                 onValueChange = { prevKeys = it },
-                label = { Text(stringResource(R.string.prev_page_key)) },
+                label = { AppText(stringResource(R.string.prev_page_key)) },
                 modifier = Modifier.Companion
                     .fillMaxWidth()
                     .onPreviewKeyEvent { event ->
@@ -72,7 +73,7 @@ fun PageKeySheet(
             OutlinedTextField(
                 value = nextKeys,
                 onValueChange = { nextKeys = it },
-                label = { Text(stringResource(R.string.next_page_key)) },
+                label = { AppText(stringResource(R.string.next_page_key)) },
                 modifier = Modifier.Companion
                     .fillMaxWidth()
                     .onPreviewKeyEvent { event ->
@@ -92,9 +93,9 @@ fun PageKeySheet(
                 singleLine = true
             )
 
-            Text(
+            AppText(
                 text = stringResource(R.string.page_key_set_help),
-                style = MaterialTheme.typography.bodyMedium,
+                style = LegadoTheme.typography.bodyMedium,
                 color = MaterialTheme.colorScheme.onSurfaceVariant
             )
 
@@ -109,7 +110,7 @@ fun PageKeySheet(
                     },
                     modifier = Modifier.Companion.weight(1f)
                 ) {
-                    Text(stringResource(R.string.reset))
+                    AppText(stringResource(R.string.reset))
                 }
 
                 Button(
@@ -120,7 +121,7 @@ fun PageKeySheet(
                     },
                     modifier = Modifier.Companion.weight(1f)
                 ) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             }
         }

+ 3 - 6
app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt

@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -20,14 +19,14 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
 import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
 import io.legado.app.ui.widget.components.settingItem.SliderSettingItem
 import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
 import org.koin.androidx.compose.koinViewModel
 
@@ -45,9 +44,7 @@ fun ReadConfigScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = {
-                    Text(stringResource(R.string.read_config))
-                },
+                title = stringResource(R.string.read_config),
                 scrollBehavior = scrollBehavior,
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBackClick)

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

@@ -17,7 +17,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -31,8 +30,10 @@ import androidx.compose.ui.res.stringResource
 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.filePicker.FilePickerSheet
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
 
@@ -72,9 +73,9 @@ fun BackgroundImageManageSheet(
                 .fillMaxWidth()
                 .padding(bottom = 24.dp)
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.background_image),
-                style = MaterialTheme.typography.titleMedium,
+                style = LegadoTheme.typography.titleMedium,
                 modifier = Modifier.padding(16.dp)
             )
 

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

@@ -20,7 +20,6 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
 import androidx.compose.foundation.lazy.grid.items
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
@@ -39,7 +38,9 @@ import io.legado.app.ui.main.Launcher4
 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.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.getCompatDrawable
 import splitties.init.appCtx
 
@@ -61,9 +62,9 @@ fun LauncherIconPickerSheet(
                 .fillMaxWidth()
                 .padding(bottom = 24.dp)
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.change_icon),
-                style = MaterialTheme.typography.titleMedium,
+                style = LegadoTheme.typography.titleMedium,
                 modifier = Modifier.padding(16.dp)
             )
 

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

@@ -21,6 +21,9 @@ object ThemeConfig {
 
     var paletteStyle by prefDelegate(PreferKey.paletteStyle, "tonalSpot")
 
+    //m3 or miuix
+    var composeEngine by prefDelegate(PreferKey.composeEngine, "m3")
+
     var materialVersion by prefDelegate(PreferKey.materialVersion, "material3")
 
     var appTheme by prefDelegate(PreferKey.appTheme, "0")

+ 22 - 14
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt

@@ -44,7 +44,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.ToggleButton
 import androidx.compose.material3.ToggleButtonDefaults
@@ -78,11 +77,10 @@ import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.OldThemeConfig
 import io.legado.app.lib.theme.ThemeStore
 import io.legado.app.lib.theme.primaryColor
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.ThemeManager
 import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
@@ -90,6 +88,9 @@ import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
 import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
 import io.legado.app.ui.widget.components.settingItem.SliderSettingItem
 import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.restart
 import io.legado.app.utils.toastOnUi
@@ -121,7 +122,7 @@ fun ThemeConfigScreen(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = { Text(stringResource(R.string.theme_setting)) },
+                title = stringResource(R.string.theme_setting),
                 scrollBehavior = scrollBehavior,
                 navigationIcon = {
                     TopbarNavigationButton(onClick = onBackClick)
@@ -226,6 +227,13 @@ fun ThemeConfigScreen(
                         context.toastOnUi(R.string.restart_to_apply)
                     }
                 )
+                DropdownListSettingItem(
+                    title = stringResource(R.string.compose_engine),
+                    selectedValue = ThemeConfig.composeEngine,
+                    displayEntries = stringArrayResource(R.array.composeEngine),
+                    entryValues = stringArrayResource(R.array.composeEngine_value),
+                    onValueChange = { ThemeConfig.composeEngine = it }
+                )
                 SliderSettingItem(
                     title = stringResource(R.string.font_scale),
                     description = stringResource(
@@ -478,7 +486,7 @@ fun ThemeConfigScreen(
     if (showRestartDialog) {
         AlertDialog(
             onDismissRequest = { showRestartDialog = false },
-            title = { Text(stringResource(R.string.restart_required_message)) },
+            title = { AppText(stringResource(R.string.restart_required_message)) },
             confirmButton = {
                 OutlinedButton(onClick = {
                     showRestartDialog = false
@@ -486,7 +494,7 @@ fun ThemeConfigScreen(
                         context.restart()
                     }, 100)
                 }) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             },
             dismissButton = {
@@ -494,7 +502,7 @@ fun ThemeConfigScreen(
                     showRestartDialog = false
                     context.toastOnUi(R.string.restart_later_message)
                 }) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
             }
         )
@@ -547,12 +555,12 @@ fun ThemeConfigScreen(
     saveThemeKey?.let { key ->
         AlertDialog(
             onDismissRequest = { saveThemeKey = null },
-            title = { Text(stringResource(R.string.theme_name)) },
+            title = { AppText(stringResource(R.string.theme_name)) },
             text = {
                 OutlinedTextField(
                     value = themeName,
                     onValueChange = { themeName = it },
-                    label = { Text("name") },
+                    label = { AppText("name") },
                     singleLine = true
                 )
             },
@@ -566,12 +574,12 @@ fun ThemeConfigScreen(
                         saveThemeKey = null
                     }
                 ) {
-                    Text(stringResource(android.R.string.ok))
+                    AppText(stringResource(android.R.string.ok))
                 }
             },
             dismissButton = {
                 TextButton(onClick = { saveThemeKey = null }) {
-                    Text(stringResource(android.R.string.cancel))
+                    AppText(stringResource(android.R.string.cancel))
                 }
             }
         )
@@ -623,7 +631,7 @@ fun ThemeModeSelector(
 
                 Spacer(Modifier.size(ToggleButtonDefaults.IconSpacing))
 
-                Text(text = label)
+                AppText(text = label)
             }
         }
     }
@@ -745,9 +753,9 @@ fun ThemeColorButton(
 
         Spacer(modifier = Modifier.height(12.dp))
 
-        Text(
+        AppText(
             text = label,
-            style = MaterialTheme.typography.labelSmall,
+            style = LegadoTheme.typography.labelSmall,
             color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
         )
     }

+ 15 - 17
app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt

@@ -15,12 +15,10 @@ import androidx.compose.material.icons.filled.Delete
 import androidx.compose.material.icons.filled.FileDownload
 import androidx.compose.material.icons.filled.Share
 import androidx.compose.material3.AlertDialog
-import androidx.compose.material3.CardDefaults
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -38,8 +36,10 @@ import androidx.core.graphics.toColorInt
 import io.legado.app.R
 import io.legado.app.help.config.OldThemeConfig
 import io.legado.app.lib.theme.primaryColor
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.GSON
 import io.legado.app.utils.getClipText
 import io.legado.app.utils.share
@@ -69,9 +69,9 @@ fun ThemeListDialog(
                     .padding(start = 16.dp, end = 8.dp, top = 8.dp, bottom = 8.dp),
                 verticalAlignment = Alignment.CenterVertically
             ) {
-                Text(
+                AppText(
                     text = stringResource(R.string.theme_list),
-                    style = MaterialTheme.typography.titleMedium,
+                    style = LegadoTheme.typography.titleMedium,
                     modifier = Modifier.weight(1f)
                 )
                 IconButton(
@@ -104,13 +104,11 @@ fun ThemeListDialog(
                             .fillMaxWidth()
                             .padding(horizontal = 16.dp),
                         shape = RoundedCornerShape(20.dp),
-                        colors = CardDefaults.cardColors(
-                            containerColor = if (item.primaryColor.toColorInt() == context.primaryColor) {
-                                MaterialTheme.colorScheme.secondaryContainer
-                            } else {
-                                MaterialTheme.colorScheme.surfaceContainer
-                            }
-                        )
+                        containerColor = if (item.primaryColor.toColorInt() == context.primaryColor) {
+                            MaterialTheme.colorScheme.secondaryContainer
+                        } else {
+                            MaterialTheme.colorScheme.surfaceContainer
+                        }
                     ) {
                         Row(
                             modifier = Modifier
@@ -129,9 +127,9 @@ fun ThemeListDialog(
                                     )
                                     .padding(8.dp)
                             )
-                            Text(
+                            AppText(
                                 text = item.themeName,
-                                style = MaterialTheme.typography.bodyLarge,
+                                style = LegadoTheme.typography.bodyLarge,
                                 modifier = Modifier.weight(1f)
                             )
                             IconButton(
@@ -161,8 +159,8 @@ fun ThemeListDialog(
     deleteIndex?.let { index ->
         AlertDialog(
             onDismissRequest = { deleteIndex = null },
-            title = { Text(stringResource(R.string.delete)) },
-            text = { Text(stringResource(R.string.sure_del)) },
+            title = { AppText(stringResource(R.string.delete)) },
+            text = { AppText(stringResource(R.string.sure_del)) },
             confirmButton = {
                 TextButton(
                     onClick = {
@@ -171,12 +169,12 @@ fun ThemeListDialog(
                         deleteIndex = null
                     }
                 ) {
-                    Text(stringResource(android.R.string.ok))
+                    AppText(stringResource(android.R.string.ok))
                 }
             },
             dismissButton = {
                 TextButton(onClick = { deleteIndex = null }) {
-                    Text(stringResource(android.R.string.cancel))
+                    AppText(stringResource(android.R.string.cancel))
                 }
             }
         )

+ 7 - 7
app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt

@@ -22,7 +22,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -38,6 +37,7 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.data.entities.DictRule
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.launch
 
 @OptIn(ExperimentalMaterial3Api::class)
@@ -69,7 +69,7 @@ fun DictRuleEditSheet(
                     .verticalScroll(rememberScrollState())
             ) {
                 CenterAlignedTopAppBar(
-                    title = { Text(stringResource(R.string.dict_rule)) },
+                    title = { AppText(stringResource(R.string.dict_rule)) },
                     navigationIcon = {
                         IconButton(onClick = onDismissRequest) {
                             Icon(
@@ -87,7 +87,7 @@ fun DictRuleEditSheet(
                             onDismissRequest = { showMenu = false }
                         ) {
                             DropdownMenuItem(
-                                text = { Text(stringResource(R.string.copy_rule)) },
+                                text = { AppText(stringResource(R.string.copy_rule)) },
                                 leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) },
                                 onClick = {
                                     onCopy(
@@ -102,7 +102,7 @@ fun DictRuleEditSheet(
                                 }
                             )
                             DropdownMenuItem(
-                                text = { Text(stringResource(R.string.paste_rule)) },
+                                text = { AppText(stringResource(R.string.paste_rule)) },
                                 leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
                                 onClick = {
                                     scope.launch {
@@ -132,20 +132,20 @@ fun DictRuleEditSheet(
                         modifier = Modifier.fillMaxWidth(),
                         value = name,
                         onValueChange = { name = it },
-                        label = { Text(stringResource(R.string.name)) },
+                        label = { AppText(stringResource(R.string.name)) },
                         singleLine = true
                     )
                     OutlinedTextField(
                         modifier = Modifier.fillMaxWidth(),
                         value = urlRule,
                         onValueChange = { urlRule = it },
-                        label = { Text(stringResource(R.string.url_rule)) }
+                        label = { AppText(stringResource(R.string.url_rule)) }
                     )
                     OutlinedTextField(
                         modifier = Modifier.fillMaxWidth(),
                         value = showRule,
                         onValueChange = { showRule = it },
-                        label = { Text(stringResource(R.string.show_rule)) },
+                        label = { AppText(stringResource(R.string.show_rule)) },
                         minLines = 3
                     )
                 }

+ 9 - 9
app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt

@@ -19,11 +19,9 @@ import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.SnackbarResult
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.rememberModalBottomSheetState
 import androidx.compose.runtime.Composable
@@ -46,6 +44,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import io.legado.app.R
 import io.legado.app.base.BaseRuleEvent
 import io.legado.app.data.entities.DictRule
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.ActionItem
 import io.legado.app.ui.widget.components.DraggableSelectionHandler
 import io.legado.app.ui.widget.components.button.SmallIconButton
@@ -59,6 +58,7 @@ import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.rules.RuleEditFields
 import io.legado.app.ui.widget.components.rules.RuleEditSheet
 import io.legado.app.ui.widget.components.rules.RuleListScaffold
+import io.legado.app.ui.widget.components.text.AppText
 import org.koin.androidx.compose.koinViewModel
 import sh.calvin.reorderable.rememberReorderableLazyListState
 
@@ -195,8 +195,8 @@ fun DictRuleScreen(
             onConfirm = { viewModel.saveImportedRules() },
             itemContent = { rule, _ ->
                 Column {
-                    Text(rule.name, style = MaterialTheme.typography.titleMedium)
-                    Text(rule.urlRule, style = MaterialTheme.typography.bodySmall, maxLines = 1)
+                    AppText(rule.name, style = LegadoTheme.typography.titleMedium)
+                    AppText(rule.urlRule, style = LegadoTheme.typography.bodySmall, maxLines = 1)
                 }
             }
         )
@@ -211,16 +211,16 @@ fun DictRuleScreen(
     showDeleteRuleDialog?.let { rule ->
         AlertDialog(
             onDismissRequest = { showDeleteRuleDialog = null },
-            title = { Text(stringResource(R.string.delete)) },
-            text = { Text(stringResource(R.string.del_msg)) },
+            title = { AppText(stringResource(R.string.delete)) },
+            text = { AppText(stringResource(R.string.del_msg)) },
             confirmButton = {
                 OutlinedButton(onClick = {
                     viewModel.delete(rule); showDeleteRuleDialog = null
-                }) { Text(stringResource(R.string.ok)) }
+                }) { AppText(stringResource(R.string.ok)) }
             },
             dismissButton = {
                 TextButton(onClick = { showDeleteRuleDialog = null }) {
-                    Text(
+                    AppText(
                         stringResource(R.string.cancel)
                     )
                 }
@@ -310,7 +310,7 @@ fun DictRuleScreen(
         snackbarHostState = snackbarHostState,
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.import_str)) },
+                text = { AppText(stringResource(R.string.import_str)) },
                 onClick = { showImportSheet = true; dismiss() },
                 leadingIcon = { Icon(Icons.Default.FileOpen, null) }
             )

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

@@ -181,7 +181,7 @@ open class MainActivity : BaseComposeActivity() {
                 (slideIntoContainer(
                     towards = AnimatedContentTransitionScope.SlideDirection.Start,
                     animationSpec = tween(
-                        durationMillis = 520,
+                        durationMillis = 480,
                         easing = FastOutSlowInEasing
                     ),
                     initialOffset = { fullWidth -> fullWidth }
@@ -193,7 +193,7 @@ open class MainActivity : BaseComposeActivity() {
                 )) togetherWith (slideOutOfContainer(
                     towards = AnimatedContentTransitionScope.SlideDirection.Start,
                     animationSpec = tween(
-                        durationMillis = 520,
+                        durationMillis = 480,
                         easing = FastOutSlowInEasing
                     ),
                     targetOffset = { fullWidth -> fullWidth / 4 }
@@ -208,7 +208,7 @@ open class MainActivity : BaseComposeActivity() {
                 (slideIntoContainer(
                     towards = AnimatedContentTransitionScope.SlideDirection.Start,
                     animationSpec = tween(
-                        durationMillis = 520,
+                        durationMillis = 480,
                         easing = FastOutSlowInEasing
                     ),
                     initialOffset = { fullWidth -> -fullWidth / 4 }
@@ -220,7 +220,7 @@ open class MainActivity : BaseComposeActivity() {
                 )) togetherWith (scaleOut(
                     targetScale = 0.8f,
                     animationSpec = tween(
-                        durationMillis = 520,
+                        durationMillis = 480,
                         easing = FastOutSlowInEasing
                     )
                 ) + fadeOut(

+ 34 - 19
app/src/main/java/io/legado/app/ui/main/MainDestination.kt

@@ -12,42 +12,57 @@ import androidx.compose.material.icons.outlined.Person
 import androidx.compose.material.icons.outlined.RssFeed
 import androidx.compose.ui.graphics.vector.ImageVector
 import io.legado.app.R
+import top.yukonga.miuix.kmp.icon.MiuixIcons
+import top.yukonga.miuix.kmp.icon.extended.Album
+import top.yukonga.miuix.kmp.icon.extended.ContactsBook
+import top.yukonga.miuix.kmp.icon.extended.Favorites
+import top.yukonga.miuix.kmp.icon.extended.Settings
 
 sealed class MainDestination(
     val route: String,
     @StringRes val labelId: Int,
-    val icon: ImageVector,
-    val selectedIcon: ImageVector
+    val m3Icon: ImageVector,
+    val m3SelectedIcon: ImageVector,
+    val miuixIcon: ImageVector,
+    val miuixSelectedIcon: ImageVector
 ) {
     object Bookshelf : MainDestination(
-        "bookshelf",
-        R.string.bookshelf,
-        Icons.AutoMirrored.Outlined.LibraryBooks,
-        Icons.AutoMirrored.Filled.LibraryBooks
+        route = "bookshelf",
+        labelId = R.string.bookshelf,
+        m3Icon = Icons.AutoMirrored.Outlined.LibraryBooks,
+        m3SelectedIcon = Icons.AutoMirrored.Filled.LibraryBooks,
+        miuixIcon = MiuixIcons.Regular.ContactsBook, // 替换为实际的 MIUIX 线框图标
+        miuixSelectedIcon = MiuixIcons.Heavy.ContactsBook // 替换为实际的 MIUIX 填充图标
     )
 
     object Explore : MainDestination(
-        "explore",
-        R.string.discovery,
-        Icons.Outlined.Explore,
-        Icons.Default.Explore
+        route = "explore",
+        labelId = R.string.discovery,
+        m3Icon = Icons.Outlined.Explore,
+        m3SelectedIcon = Icons.Default.Explore,
+        miuixIcon = MiuixIcons.Regular.Album,
+        miuixSelectedIcon = MiuixIcons.Heavy.Album
     )
 
     object Rss : MainDestination(
-        "rss",
-        R.string.rss,
-        Icons.Outlined.RssFeed,
-        Icons.Default.RssFeed
+        route = "rss",
+        labelId = R.string.rss,
+        m3Icon = Icons.Outlined.RssFeed,
+        m3SelectedIcon = Icons.Default.RssFeed,
+        miuixIcon = MiuixIcons.Regular.Favorites,
+        miuixSelectedIcon = MiuixIcons.Heavy.Favorites
     )
 
     object My : MainDestination(
-        "my",
-        R.string.my,
-        Icons.Outlined.Person,
-        Icons.Default.Person
+        route = "my",
+        labelId = R.string.my,
+        m3Icon = Icons.Outlined.Person,
+        m3SelectedIcon = Icons.Default.Person,
+        miuixIcon = MiuixIcons.Regular.Settings,
+        miuixSelectedIcon = MiuixIcons.Heavy.Settings
     )
 
     companion object {
         val mainDestinations = listOf(Bookshelf, Explore, Rss, My)
     }
-}
+}

+ 22 - 94
app/src/main/java/io/legado/app/ui/main/MainScreen.kt

@@ -20,17 +20,12 @@ import androidx.compose.material.icons.filled.Menu
 import androidx.compose.material.icons.filled.Search
 import androidx.compose.material3.Badge
 import androidx.compose.material3.BadgedBox
-import androidx.compose.material3.BottomAppBarDefaults
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.ExtendedFloatingActionButton
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.NavigationBar
-import androidx.compose.material3.NavigationBarItem
-import androidx.compose.material3.NavigationBarItemDefaults
-import androidx.compose.material3.Text
 import androidx.compose.material3.WideNavigationRail
 import androidx.compose.material3.WideNavigationRailItem
 import androidx.compose.material3.WideNavigationRailValue
@@ -56,17 +51,19 @@ import io.legado.app.R
 import io.legado.app.ui.book.info.BookInfoActivity
 import io.legado.app.ui.book.search.SearchActivity
 import io.legado.app.ui.config.mainConfig.MainConfig
-import io.legado.app.ui.config.themeConfig.ThemeConfig
 import io.legado.app.ui.main.bookshelf.BookshelfScreen
 import io.legado.app.ui.main.bookshelf.BookshelfViewModel
 import io.legado.app.ui.main.explore.ExploreScreen
 import io.legado.app.ui.main.my.MyScreen
 import io.legado.app.ui.main.rss.RssScreen
 import io.legado.app.ui.theme.regularHazeEffect
+import io.legado.app.ui.widget.components.AppNavigationBar
+import io.legado.app.ui.widget.components.AppNavigationBarItem
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.GlassDefaults
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.startActivity
 import io.legado.app.utils.startActivityForBook
 import kotlinx.coroutines.launch
@@ -151,7 +148,7 @@ fun MainScreen(
                             onClick = { context.startActivity<SearchActivity>() },
                             expanded = expanded,
                             icon = { Icon(Icons.Default.Search, contentDescription = null) },
-                            text = { Text(stringResource(R.string.search)) }
+                            text = { AppText(stringResource(R.string.search)) }
                         )
                     }
                 }
@@ -198,7 +195,7 @@ fun MainScreen(
                                     ) { dismiss ->
                                         bookshelfUiState.groups.forEachIndexed { groupIndex, group ->
                                             RoundDropdownMenuItem(
-                                                text = { Text(group.groupName) },
+                                                text = { AppText(group.groupName) },
                                                 onClick = {
                                                     coroutineScope.launch {
                                                         if (pagerState.currentPage != index) {
@@ -224,7 +221,7 @@ fun MainScreen(
                             }
                         },
                         label = if (labelVisibilityMode != "unlabeled") {
-                            { Text(stringResource(destination.labelId)) }
+                            { AppText(stringResource(destination.labelId)) }
                         } else null
                     )
                 }
@@ -237,103 +234,34 @@ fun MainScreen(
                 if (!useRail && MainConfig.showBottomView) {
                     val labelVisibilityMode = MainConfig.labelVisibilityMode
                     val isUnlabeled = labelVisibilityMode == "unlabeled"
-                    NavigationBar(
+
+                    AppNavigationBar(
                         modifier = Modifier
                             .regularHazeEffect(state = hazeState)
-                            .height(if (isUnlabeled) 64.dp else 80.dp),
-                        containerColor = GlassDefaults.glassColor(
-                            noBlurColor = BottomAppBarDefaults.containerColor,
-                            blurAlpha = GlassDefaults.DefaultBlurAlpha
-                        ).let { baseColor ->
-                            val opacity = (ThemeConfig.bottomBarOpacity.coerceIn(0, 100)) / 100f
-                            baseColor.copy(alpha = (baseColor.alpha * opacity).coerceIn(0f, 1f))
-                        }
+                            .height(if (isUnlabeled) 64.dp else 80.dp)
                     ) {
                         val alwaysShowLabel = when (labelVisibilityMode) {
                             "labeled" -> true
-                            "selected" -> false
-                            "unlabeled" -> false
                             else -> false
                         }
                         destinations.forEachIndexed { index, destination ->
                             val selected = pagerState.targetPage == index
-                            var showGroupMenu by remember { mutableStateOf(false) }
-                            val haptic = LocalHapticFeedback.current
-
-                            NavigationBarItem(
+                            AppNavigationBarItem(
                                 selected = selected,
                                 onClick = {
-                                    coroutineScope.launch {
-                                        pagerState.animateScrollToPage(index)
-                                    }
+                                    coroutineScope.launch { pagerState.animateScrollToPage(index) }
                                 },
-                                icon = {
-                                    Box {
-                                        NavigationIcon(
-                                            destination = destination,
-                                            selected = selected,
-                                            upBooksCount = uiState.upBooksCount,
-                                            modifier = if (destination == MainDestination.Bookshelf) {
-                                                Modifier.combinedClickable(
-                                                    onClick = {
-                                                        coroutineScope.launch {
-                                                            pagerState.animateScrollToPage(index)
-                                                        }
-                                                    },
-                                                    onLongClick = {
-                                                        haptic.performHapticFeedback(
-                                                            HapticFeedbackType.LongPress
-                                                        )
-                                                        showGroupMenu = true
-                                                    }
-                                                )
-                                            } else Modifier
-                                        )
-
-                                        if (destination == MainDestination.Bookshelf && showGroupMenu) {
-                                            RoundDropdownMenu(
-                                                expanded = showGroupMenu,
-                                                onDismissRequest = { showGroupMenu = false }
-                                            ) { dismiss ->
-                                                bookshelfUiState.groups.forEachIndexed { groupIndex, group ->
-                                                    RoundDropdownMenuItem(
-                                                        text = { Text(group.groupName) },
-                                                        onClick = {
-                                                            coroutineScope.launch {
-                                                                if (pagerState.currentPage != index) {
-                                                                    pagerState.scrollToPage(index)
-                                                                }
-                                                                bookshelfViewModel.changeGroup(
-                                                                    group.groupId
-                                                                )
-                                                                dismiss()
-                                                            }
-                                                        },
-                                                        trailingIcon = {
-                                                            if (bookshelfUiState.selectedGroupIndex == groupIndex) {
-                                                                Icon(
-                                                                    Icons.Default.Check,
-                                                                    null,
-                                                                    modifier = Modifier.size(18.dp)
-                                                                )
-                                                            }
-                                                        }
-                                                    )
-                                                }
-                                            }
-                                        }
-                                    }
+                                labelString = stringResource(destination.labelId),
+                                miuixIcon = if (selected) destination.miuixSelectedIcon else destination.miuixIcon,
+                                m3Icon = {
+                                    if (selected) destination.m3SelectedIcon else destination.m3Icon
                                 },
-                                colors = NavigationBarItemDefaults.colors(
-                                    indicatorColor = GlassDefaults.glassColor(
-                                        noBlurColor = MaterialTheme.colorScheme.secondaryContainer,
-                                        blurAlpha = GlassDefaults.ThickBlurAlpha
-                                    ),
+                                m3IndicatorColor = GlassDefaults.glassColor(
+                                    noBlurColor = MaterialTheme.colorScheme.secondaryContainer,
+                                    blurAlpha = GlassDefaults.ThickBlurAlpha
                                 ),
-                                label = if (labelVisibilityMode != "unlabeled") {
-                                    { Text(stringResource(destination.labelId)) }
-                                } else null,
-                                alwaysShowLabel = alwaysShowLabel
+                                m3ShowLabel = !isUnlabeled,
+                                m3AlwaysShowLabel = alwaysShowLabel
                             )
                         }
                     }
@@ -386,10 +314,10 @@ private fun NavigationIcon(
     upBooksCount: Int,
     modifier: Modifier = Modifier
 ) {
-    val icon = if (selected) destination.selectedIcon else destination.icon
+    val icon = if (selected) destination.m3SelectedIcon else destination.m3Icon
     Box(modifier = modifier) {
         if (destination == MainDestination.Bookshelf && upBooksCount > 0) {
-            BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) {
+            BadgedBox(badge = { Badge { AppText(upBooksCount.toString()) } }) {
                 Icon(icon, contentDescription = null)
             }
         } else {

+ 17 - 16
app/src/main/java/io/legado/app/ui/main/bookshelf/BookItem.kt

@@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.HorizontalDivider
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -34,9 +33,11 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.data.entities.BookGroup
 import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.cover.BookCover
 import io.legado.app.ui.widget.components.cover.BookshelfCover
 import io.legado.app.ui.widget.components.cover.Cover
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.toTimeAgo
 
 /**
@@ -88,9 +89,9 @@ fun BookshelfItem(
                 ) {
                     cover(Modifier.fillMaxSize())
                     if (gridStyle == 1) {
-                        Text(
+                        AppText(
                             text = title,
-                            style = (if (titleSmallFont) MaterialTheme.typography.labelSmall else MaterialTheme.typography.labelMedium).copy(
+                            style = (if (titleSmallFont) LegadoTheme.typography.labelSmall else LegadoTheme.typography.labelMedium).copy(
                                 color = Color.White,
                                 shadow = Shadow(
                                     color = Color.Black.copy(alpha = 0.5f),
@@ -117,9 +118,9 @@ fun BookshelfItem(
                 }
 
                 if (gridStyle == 0) {
-                    Text(
+                    AppText(
                         text = title,
-                        style = if (titleSmallFont) MaterialTheme.typography.labelSmall else MaterialTheme.typography.labelMedium,
+                        style = if (titleSmallFont) LegadoTheme.typography.labelSmall else LegadoTheme.typography.labelMedium,
                         maxLines = titleMaxLines,
                         overflow = TextOverflow.Ellipsis,
                         textAlign = if (titleCenter) TextAlign.Center else TextAlign.Start,
@@ -152,16 +153,16 @@ fun BookshelfItem(
                     modifier = Modifier.weight(1f),
                     verticalArrangement = Arrangement.Center
                 ) {
-                    Text(
+                    AppText(
                         text = title,
-                        style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold),
+                        style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold),
                         maxLines = if (!isCompact) 2 else 1,
                         overflow = TextOverflow.Ellipsis
                     )
                     subTitle?.let {
-                        Text(
+                        AppText(
                             text = it,
-                            style = MaterialTheme.typography.bodySmall,
+                            style = LegadoTheme.typography.bodySmall,
                             maxLines = 1,
                             overflow = TextOverflow.Ellipsis,
                             modifier = Modifier.padding(top = 2.dp)
@@ -169,9 +170,9 @@ fun BookshelfItem(
                     }
                     if (!isCompact) {
                         desc?.let {
-                            Text(
+                            AppText(
                                 text = it,
-                                style = MaterialTheme.typography.bodySmall,
+                                style = LegadoTheme.typography.bodySmall,
                                 maxLines = 1,
                                 overflow = TextOverflow.Ellipsis,
                                 modifier = Modifier.padding(top = 2.dp)
@@ -372,7 +373,7 @@ fun BookItem(
                 isUpdating = isUpdating,
                 modifier = modifier,
                 badgeText = if (BookshelfConfig.showUnread && unreadCount > 0) unreadCount.toString() else null,
-                showBadgeDot = !BookshelfConfig.showUnread && BookshelfConfig.showUnreadNew && unreadCount > 0
+                showBadgeDot = BookshelfConfig.showUnread && BookshelfConfig.showUnreadNew && book.isNew
             )
         },
         title = book.name,
@@ -384,16 +385,16 @@ fun BookItem(
         desc = stringResource(R.string.read_dur_progress, book.durChapterTitle ?: ""),
         extra = {
             if (BookshelfConfig.showLastUpdateTime && !book.isLocal) {
-                Text(
+                AppText(
                     text = book.latestChapterTime.toTimeAgo(),
-                    style = MaterialTheme.typography.bodySmall,
+                    style = LegadoTheme.typography.bodySmall,
                     color = if (layoutMode != 0 || !isCompact) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary,
                     modifier = Modifier.padding(end = 4.dp)
                 )
             }
-            Text(
+            AppText(
                 text = book.latestChapterTitle ?: "",
-                style = MaterialTheme.typography.bodySmall,
+                style = LegadoTheme.typography.bodySmall,
                 maxLines = 1,
                 overflow = TextOverflow.Ellipsis,
                 modifier = Modifier.weight(1f)

+ 4 - 0
app/src/main/java/io/legado/app/ui/main/bookshelf/BookShelfItem.kt

@@ -16,6 +16,7 @@ data class BookShelfItem(
     val durChapterPos: Int,
     val latestChapterTitle: String?,
     val latestChapterTime: Long,
+    val lastCheckCount: Int,
     val totalChapterNum: Int,
     val durChapterIndex: Int,
     val type: Int,
@@ -33,5 +34,8 @@ data class BookShelfItem(
 
     val isNotShelf: Boolean get() = (type and BookType.notShelf) > 0
 
+    val isNew: Boolean get() = lastCheckCount > 0
+
+
     fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0)
 }

+ 4 - 3
app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt

@@ -23,7 +23,6 @@ import androidx.compose.material.icons.filled.TextFormat
 import androidx.compose.material.icons.filled.ViewCompact
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalConfiguration
@@ -32,10 +31,12 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem
 import io.legado.app.ui.widget.components.settingItem.CompactSliderSettingItem
 import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -55,9 +56,9 @@ fun BookshelfConfigSheet(
                 .padding(bottom = 32.dp),
             verticalArrangement = Arrangement.spacedBy(8.dp)
         ) {
-            Text(
+            AppText(
                 text = stringResource(R.string.bookshelf_layout),
-                style = MaterialTheme.typography.titleLarge,
+                style = LegadoTheme.typography.titleLarge,
                 modifier = Modifier.padding(vertical = 16.dp)
             )
 

+ 27 - 39
app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt

@@ -45,7 +45,7 @@ import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.SnackbarResult
 import androidx.compose.material3.Surface
 import androidx.compose.material3.Tab
-import androidx.compose.material3.Text
+import io.legado.app.ui.widget.components.text.AppText
 import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
 import androidx.compose.material3.pulltorefresh.pullToRefresh
 import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
@@ -78,6 +78,7 @@ import io.legado.app.ui.book.import.remote.RemoteBookActivity
 import io.legado.app.ui.book.manage.BookshelfManageActivity
 import io.legado.app.ui.book.search.SearchActivity
 import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton
 import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
 import io.legado.app.ui.widget.components.importComponents.SourceInputDialog
@@ -85,6 +86,7 @@ import io.legado.app.ui.widget.components.lazylist.FastScrollLazyVerticalGrid
 import io.legado.app.ui.widget.components.list.ListScaffold
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.tabRow.AdaptiveTabRow
 import io.legado.app.utils.readText
 import io.legado.app.utils.startActivity
 import io.legado.app.utils.toastOnUi
@@ -235,37 +237,37 @@ fun BookshelfScreen(
         topBarActions = { },
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.add_remote_book)) },
+                text = { AppText(stringResource(R.string.add_remote_book)) },
                 onClick = { context.startActivity<RemoteBookActivity>(); dismiss() },
                 leadingIcon = { Icon(Icons.Default.Wifi, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.book_local)) },
+                text = { AppText(stringResource(R.string.book_local)) },
                 onClick = { context.startActivity<ImportBookActivity>(); dismiss() },
                 leadingIcon = { Icon(Icons.Default.Save, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.update_toc)) },
+                text = { AppText(stringResource(R.string.update_toc)) },
                 onClick = { viewModel.upToc(uiState.items); dismiss() },
                 leadingIcon = { Icon(Icons.Default.Refresh, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text("布局设置") },
+                text = { AppText("布局设置") },
                 onClick = { showConfigSheet = true; dismiss() },
                 leadingIcon = { Icon(Icons.Default.GridView, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.group_manage)) },
+                text = { AppText(stringResource(R.string.group_manage)) },
                 onClick = { showGroupManageSheet = true; dismiss() },
                 leadingIcon = { Icon(Icons.Default.Edit, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.add_url)) },
+                text = { AppText(stringResource(R.string.add_url)) },
                 onClick = { showAddUrlDialog = true; dismiss() },
                 leadingIcon = { Icon(Icons.Default.Link, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.bookshelf_management)) },
+                text = { AppText(stringResource(R.string.bookshelf_management)) },
                 onClick = {
                     val groupId =
                         uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L
@@ -277,7 +279,7 @@ fun BookshelfScreen(
                 leadingIcon = { Icon(Icons.Default.Settings, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.cache_export)) },
+                text = { AppText(stringResource(R.string.cache_export)) },
                 onClick = {
                     val groupId =
                         uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L
@@ -289,7 +291,7 @@ fun BookshelfScreen(
                 leadingIcon = { Icon(Icons.Default.Download, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.export_bookshelf)) },
+                text = { AppText(stringResource(R.string.export_bookshelf)) },
                 onClick = {
                     showExportSheet = true
                     dismiss()
@@ -297,12 +299,12 @@ fun BookshelfScreen(
                 leadingIcon = { Icon(Icons.Default.ImportExport, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.import_bookshelf)) },
+                text = { AppText(stringResource(R.string.import_bookshelf)) },
                 onClick = { showImportSheet = true; dismiss() },
                 leadingIcon = { Icon(Icons.Default.FileOpen, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.log)) },
+                text = { AppText(stringResource(R.string.log)) },
                 onClick = {
                     showLogSheet = true
                     dismiss()
@@ -320,32 +322,18 @@ fun BookshelfScreen(
                         modifier = Modifier.fillMaxWidth(),
                         verticalAlignment = Alignment.CenterVertically
                     ) {
-                        PrimaryScrollableTabRow(
+                        val tabTitles = remember(uiState.groups) {
+                            uiState.groups.map { it.groupName }
+                        }
+
+                        AdaptiveTabRow(
+                            tabTitles = tabTitles,
                             selectedTabIndex = selectedTabIndex,
-                            edgePadding = 0.dp,
-                            divider = { },
-                            containerColor = Color.Transparent,
-                            minTabWidth = 0.dp,
+                            onTabSelected = { index ->
+                                scope.launch { pagerState.animateScrollToPage(index) }
+                            },
                             modifier = Modifier.weight(1f)
-                        ) {
-                            uiState.groups.forEachIndexed { index, group ->
-                                Tab(
-                                    selected = selectedTabIndex == index,
-                                    onClick = {
-                                        scope.launch { pagerState.animateScrollToPage(index) }
-                                    },
-                                    text = {
-                                        Text(
-                                            text = group.groupName,
-                                            maxLines = 1,
-                                            overflow = TextOverflow.Ellipsis,
-                                            modifier = Modifier.padding(horizontal = 8.dp),
-                                            color = MaterialTheme.colorScheme.onSurfaceVariant
-                                        )
-                                    }
-                                )
-                            }
-                        }
+                        )
 
                         if (BookshelfConfig.shouldShowExpandButton) {
                             Box(modifier = Modifier.padding(end = 16.dp)) {
@@ -361,7 +349,7 @@ fun BookshelfScreen(
                                 ) { dismiss ->
                                     uiState.groups.forEachIndexed { index, group ->
                                         RoundDropdownMenuItem(
-                                            text = { Text(group.groupName) },
+                                            text = { AppText(group.groupName) },
                                             onClick = {
                                                 scope.launch { pagerState.animateScrollToPage(index) }
                                                 dismiss()
@@ -565,10 +553,10 @@ fun BookshelfScreen(
                 ) {
                     CircularProgressIndicator()
                     uiState.loadingText?.let {
-                        Text(
+                        AppText(
                             text = it,
                             modifier = Modifier.padding(top = 16.dp),
-                            style = MaterialTheme.typography.bodyMedium
+                            style = LegadoTheme.typography.bodyMedium
                         )
                     }
                 }

+ 4 - 3
app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt

@@ -19,7 +19,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.collectAsState
@@ -36,8 +35,10 @@ import io.legado.app.R
 import io.legado.app.data.entities.BookGroup
 import io.legado.app.ui.book.group.GroupEditContent
 import io.legado.app.ui.book.group.GroupViewModel
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.card.ReorderableSelectionItem
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.move
 import org.koin.androidx.compose.koinViewModel
 import sh.calvin.reorderable.rememberReorderableLazyListState
@@ -104,9 +105,9 @@ fun GroupManageSheet(
                         horizontalArrangement = Arrangement.SpaceBetween,
                         verticalAlignment = Alignment.CenterVertically
                     ) {
-                        Text(
+                        AppText(
                             text = stringResource(R.string.group_manage),
-                            style = MaterialTheme.typography.titleLarge
+                            style = LegadoTheme.typography.titleLarge
                         )
                         IconButton(onClick = {
                             editingGroup = null

+ 39 - 30
app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt

@@ -43,7 +43,6 @@ import androidx.compose.material3.ListItemDefaults
 import androidx.compose.material3.LocalMinimumInteractiveComponentSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedCard
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
@@ -73,6 +72,9 @@ import io.legado.app.ui.book.search.SearchActivity
 import io.legado.app.ui.book.search.SearchScope
 import io.legado.app.ui.book.source.edit.BookSourceEditActivity
 import io.legado.app.ui.login.SourceLoginActivity
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.divider.PillHeaderDivider
@@ -81,9 +83,11 @@ import io.legado.app.ui.widget.components.list.ListScaffold
 import io.legado.app.ui.widget.components.menuItem.MenuItemIcon
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.startActivity
 import kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
+import top.yukonga.miuix.kmp.theme.MiuixTheme
 import kotlin.math.roundToInt
 
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@@ -148,13 +152,13 @@ fun ExploreScreen(
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
                 leadingIcon = { MenuItemIcon(Icons.Default.Group) },
-                text = { Text(stringResource(R.string.all)) },
+                text = { AppText(stringResource(R.string.all)) },
                 onClick = { viewModel.setGroup(""); dismiss() }
             )
             uiState.groups.forEach { group ->
                 RoundDropdownMenuItem(
                     leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) },
-                    text = { Text(group) },
+                    text = { AppText(group) },
                     onClick = { viewModel.setGroup(group); dismiss() }
                 )
             }
@@ -274,19 +278,19 @@ fun ExploreScreen(
     sourceToDelete?.let { source ->
         AlertDialog(
             onDismissRequest = { sourceToDelete = null },
-            title = { Text(stringResource(R.string.draw)) },
-            text = { Text(stringResource(R.string.sure_del) + "\n" + source.bookSourceName) },
+            title = { AppText(stringResource(R.string.draw)) },
+            text = { AppText(stringResource(R.string.sure_del) + "\n" + source.bookSourceName) },
             confirmButton = {
                 TextButton(onClick = {
                     viewModel.deleteSource(source)
                     sourceToDelete = null
                 }) {
-                    Text(stringResource(R.string.yes))
+                    AppText(stringResource(R.string.yes))
                 }
             },
             dismissButton = {
                 TextButton(onClick = { sourceToDelete = null }) {
-                    Text(stringResource(R.string.no))
+                    AppText(stringResource(R.string.no))
                 }
             }
         )
@@ -344,11 +348,22 @@ fun ExploreSourceHeader(
 ) {
     var showMenu by remember { mutableStateOf(false) }
     val rotation by animateFloatAsState(if (isExpanded) 90f else 0f, label = "rotation")
+
+    val composeEngine = ThemeResolver.isMiuixEngine(composeEngine)
     val containerColor by animateColorAsState(
         targetValue = if (isExpanded)
-            MaterialTheme.colorScheme.secondaryContainer
+            if (composeEngine) MiuixTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.secondaryContainer
         else
-            MaterialTheme.colorScheme.surfaceContainerLow,
+            if (composeEngine) MiuixTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.surfaceContainerLow,
+        animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing),
+        label = "CardColor"
+    )
+
+    val contentColor by animateColorAsState(
+        targetValue = if (isExpanded)
+            if (composeEngine) MiuixTheme.colorScheme.primary else MaterialTheme.colorScheme.primary
+        else
+            if (composeEngine) MiuixTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurface,
         animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing),
         label = "CardColor"
     )
@@ -358,7 +373,7 @@ fun ExploreSourceHeader(
             .fillMaxWidth()
             .padding(horizontal = 16.dp, vertical = 4.dp),
         shape = MaterialTheme.shapes.medium,
-        colors = CardDefaults.cardColors(containerColor = containerColor),
+        containerColor = containerColor
     ) {
         ListItem(
             modifier = Modifier
@@ -371,14 +386,10 @@ fun ExploreSourceHeader(
                 containerColor = Color.Transparent
             ),
             headlineContent = {
-                Text(
+                AppText(
                     text = item.bookSourceName,
-                    style = MaterialTheme.typography.titleMedium,
-                    color = if (isExpanded) {
-                        MaterialTheme.colorScheme.primary
-                    } else {
-                        MaterialTheme.colorScheme.onSurface
-                    }
+                    style = LegadoTheme.typography.titleMedium,
+                    color = contentColor
                 )
             },
             trailingContent = {
@@ -401,29 +412,29 @@ fun ExploreSourceHeader(
                     PillHeaderDivider(title = item.bookSourceName)
                     RoundDropdownMenuItem(
                         leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) },
-                        text = { Text(stringResource(R.string.to_top)) },
+                        text = { AppText(stringResource(R.string.to_top)) },
                         onClick = { onTop(); showMenu = false }
                     )
                     RoundDropdownMenuItem(
                         leadingIcon = { MenuItemIcon(Icons.Default.Edit) },
-                        text = { Text(stringResource(R.string.edit)) },
+                        text = { AppText(stringResource(R.string.edit)) },
                         onClick = { onEdit(); showMenu = false }
                     )
                     RoundDropdownMenuItem(
                         leadingIcon = { MenuItemIcon(Icons.Default.Search) },
-                        text = { Text(stringResource(R.string.search)) },
+                        text = { AppText(stringResource(R.string.search)) },
                         onClick = { onSearch(); showMenu = false }
                     )
                     if (item.hasLoginUrl) {
                         RoundDropdownMenuItem(
                             leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) },
-                            text = { Text(stringResource(R.string.login)) },
+                            text = { AppText(stringResource(R.string.login)) },
                             onClick = { onLogin(); showMenu = false }
                         )
                     }
                     RoundDropdownMenuItem(
                         leadingIcon = { MenuItemIcon(Icons.Default.Refresh) },
-                        text = { Text(stringResource(R.string.refresh)) },
+                        text = { AppText(stringResource(R.string.refresh)) },
                         onClick = { onRefresh(); showMenu = false }
                     )
                     RoundDropdownMenuItem(
@@ -434,7 +445,7 @@ fun ExploreSourceHeader(
                             )
                         },
                         text = {
-                            Text(
+                            AppText(
                                 stringResource(R.string.delete),
                                 color = MaterialTheme.colorScheme.error
                             )
@@ -455,7 +466,7 @@ fun ExploreStickyCard(
     TextCard(
         text = item.bookSourceName,
         backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh,
-        textStyle = MaterialTheme.typography.labelLarge,
+        textStyle = LegadoTheme.typography.labelLarge,
         horizontalPadding = 8.dp,
         verticalPadding = 6.dp,
         onClick = onClick
@@ -479,10 +490,8 @@ fun ExploreKindItem(
             GlassCard(
                 onClick = onClick,
                 shape = shape,
-                colors = CardDefaults.cardColors(
-                    containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.6f),
-                    contentColor = MaterialTheme.colorScheme.onSecondaryContainer
-                ),
+                containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.6f),
+                contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
                 modifier = modifier
             ) {
                 KindText(kind)
@@ -506,12 +515,12 @@ fun ExploreKindItem(
 private fun KindText(
     kind: ExploreKind
 ) {
-    Text(
+    AppText(
         text = kind.title,
         modifier = Modifier
             .fillMaxWidth()
             .padding(vertical = 8.dp),
-        style = MaterialTheme.typography.labelMediumEmphasized,
+        style = LegadoTheme.typography.labelMediumEmphasized,
         textAlign = TextAlign.Center,
         overflow = TextOverflow.Ellipsis,
         maxLines = 1

+ 88 - 59
app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt

@@ -1,13 +1,20 @@
 package io.legado.app.ui.main.my
 
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.expandVertically
+import androidx.compose.animation.shrinkVertically
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.only
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.icons.Icons
@@ -16,20 +23,19 @@ import androidx.compose.material.icons.automirrored.filled.HelpOutline
 import androidx.compose.material.icons.automirrored.filled.LibraryBooks
 import androidx.compose.material.icons.automirrored.filled.Rule
 import androidx.compose.material.icons.filled.Bookmark
+import androidx.compose.material.icons.filled.ContentCopy
 import androidx.compose.material.icons.filled.FindReplace
 import androidx.compose.material.icons.filled.Folder
 import androidx.compose.material.icons.filled.History
 import androidx.compose.material.icons.filled.Info
+import androidx.compose.material.icons.filled.OpenInBrowser
 import androidx.compose.material.icons.filled.Settings
 import androidx.compose.material.icons.filled.Source
 import androidx.compose.material.icons.filled.Web
-import androidx.compose.material3.DropdownMenuItem
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
-import androidx.compose.material3.Switch
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
@@ -46,11 +52,14 @@ import io.legado.app.ui.book.toc.rule.TxtTocRuleActivity
 import io.legado.app.ui.dict.rule.DictRuleActivity
 import io.legado.app.ui.file.FileManageActivity
 import io.legado.app.ui.replace.ReplaceRuleActivity
+import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SplicedColumnGroup
-import io.legado.app.ui.widget.components.settingItem.SettingItem
+import io.legado.app.ui.widget.components.button.SmallTextButton
+import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
+import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
+import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 
 
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@@ -70,11 +79,7 @@ fun MyScreen(
             .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top),
         topBar = {
             GlassMediumFlexibleTopAppBar(
-                title = {
-                    Text(
-                        text = stringResource(R.string.my)
-                    )
-                },
+                title = stringResource(R.string.my),
                 actions = {
                     IconButton(
                         onClick = { onNavigate(PrefClickEvent.ShowMd("appHelp", "xxx")) }
@@ -99,52 +104,21 @@ fun MyScreen(
             )
 
             SplicedColumnGroup(
-                modifier = Modifier.padding(horizontal = 16.dp),
+                modifier = Modifier.adaptiveHorizontalPadding(),
                 title = ""
             ) {
-                SettingItem(
-                    title = stringResource(R.string.web_service),
-                    description = if (uiState.isWebServiceRun)
-                        uiState.webServiceAddress
-                    else
-                        stringResource(R.string.web_service_desc),
-                    imageVector = Icons.Default.Web,
-                    trailingContent = {
-                        Switch(
-                            checked = uiState.isWebServiceRun,
-                            onCheckedChange = {
-                                viewModel.onEvent(PrefClickEvent.ToggleWebService)
-                            }
-                        )
-                    },
-                    dropdownMenu = if (uiState.isWebServiceRun) {
-                        { onDismiss ->
-                            DropdownMenuItem(
-                                text = { Text("复制地址") },
-                                onClick = {
-                                    onNavigate(PrefClickEvent.CopyUrl(uiState.webServiceAddress))
-                                    onDismiss()
-                                }
-                            )
-                            DropdownMenuItem(
-                                text = { Text("浏览器打开") },
-                                onClick = {
-                                    onNavigate(PrefClickEvent.OpenUrl(uiState.webServiceAddress))
-                                    onDismiss()
-                                }
-                            )
-                        }
-                    } else null,
-                    onClick = { }
+                WebServiceSettingBlock(
+                    uiState = uiState,
+                    viewModel = viewModel,
+                    onNavigate = onNavigate
                 )
             }
 
-
             SplicedColumnGroup(
-                modifier = Modifier.padding(horizontal = 16.dp),
+                modifier = Modifier.adaptiveHorizontalPadding(),
                 title = "规则"
             ) {
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.book_source_manage),
                     description = stringResource(R.string.book_source_manage_desc),
                     imageVector = Icons.Default.Source,
@@ -154,7 +128,7 @@ fun MyScreen(
                         )
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.replace_purify),
                     imageVector = Icons.Default.FindReplace,
                     onClick = {
@@ -163,7 +137,7 @@ fun MyScreen(
                         )
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.txt_toc_rule),
                     imageVector = Icons.AutoMirrored.Filled.Rule,
                     onClick = {
@@ -172,7 +146,7 @@ fun MyScreen(
                         )
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.dict_rule),
                     imageVector = Icons.AutoMirrored.Filled.LibraryBooks,
                     onClick = {
@@ -184,44 +158,44 @@ fun MyScreen(
             }
 
             SplicedColumnGroup(
-                modifier = Modifier.padding(horizontal = 16.dp),
+                modifier = Modifier.adaptiveHorizontalPadding(),
                 title = stringResource(R.string.other)) {
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.setting),
                     imageVector = Icons.Default.Settings,
                     onClick = {
                         onOpenSettings()
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.bookmark),
                     imageVector = Icons.Default.Bookmark,
                     onClick = {
                         onNavigate(PrefClickEvent.StartActivity(AllBookmarkActivity::class.java))
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.read_record),
                     imageVector = Icons.Default.History,
                     onClick = {
                         onNavigate(PrefClickEvent.StartActivity(ReadRecordActivity::class.java))
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.file_manage),
                     imageVector = Icons.Default.Folder,
                     onClick = {
                         onNavigate(PrefClickEvent.StartActivity(FileManageActivity::class.java))
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.about),
                     imageVector = Icons.Default.Info,
                     onClick = {
                         onNavigate(PrefClickEvent.StartActivity(AboutActivity::class.java))
                     }
                 )
-                SettingItem(
+                ClickableSettingItem(
                     title = stringResource(R.string.exit),
                     imageVector = Icons.AutoMirrored.Filled.ExitToApp,
                     onClick = {
@@ -234,3 +208,58 @@ fun MyScreen(
         }
     }
 }
+
+
+@Composable
+fun WebServiceSettingBlock(
+    uiState: MyUiState,
+    viewModel: MyViewModel,
+    onNavigate: (PrefClickEvent) -> Unit
+) {
+    Column(modifier = Modifier.fillMaxWidth()) {
+        SwitchSettingItem(
+            title = stringResource(R.string.web_service),
+            description = if (uiState.isWebServiceRun) {
+                uiState.webServiceAddress
+            } else {
+                stringResource(R.string.web_service_desc)
+            },
+            imageVector = Icons.Default.Web,
+            checked = uiState.isWebServiceRun,
+            onCheckedChange = {
+                viewModel.onEvent(PrefClickEvent.ToggleWebService)
+            }
+        )
+
+        AnimatedVisibility(
+            visible = uiState.isWebServiceRun,
+            enter = expandVertically(),
+            exit = shrinkVertically()
+        ) {
+            Row(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .padding(start = 16.dp, end = 16.dp, bottom = 12.dp),
+                horizontalArrangement = Arrangement.End
+            ) {
+                SmallTextButton(
+                    text = "复制地址",
+                    icon = Icons.Default.ContentCopy,
+                    onClick = {
+                        onNavigate(PrefClickEvent.CopyUrl(uiState.webServiceAddress))
+                    }
+                )
+
+                Spacer(modifier = Modifier.width(12.dp))
+
+                SmallTextButton(
+                    text = "浏览器打开",
+                    icon = Icons.Default.OpenInBrowser,
+                    onClick = {
+                        onNavigate(PrefClickEvent.OpenUrl(uiState.webServiceAddress))
+                    }
+                )
+            }
+        }
+    }
+}

+ 16 - 15
app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt

@@ -30,7 +30,6 @@ import androidx.compose.material.icons.filled.VerticalAlignTop
 import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
@@ -55,6 +54,7 @@ import io.legado.app.ui.rss.read.ReadRssActivity
 import io.legado.app.ui.rss.source.edit.RssSourceEditActivity
 import io.legado.app.ui.rss.source.manage.RssSourceActivity
 import io.legado.app.ui.rss.subscription.RuleSubActivity
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.SourceIcon
 import io.legado.app.ui.widget.components.button.TopBarActionButton
 import io.legado.app.ui.widget.components.divider.PillDivider
@@ -63,6 +63,7 @@ import io.legado.app.ui.widget.components.list.ListScaffold
 import io.legado.app.ui.widget.components.menuItem.MenuItemIcon
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.openUrl
 import io.legado.app.utils.startActivity
 import org.koin.androidx.compose.koinViewModel
@@ -135,12 +136,12 @@ fun RssScreen(
                     dismiss()
                 },
                 leadingIcon = { MenuItemIcon(Icons.Default.Settings) },
-                text = { Text("订阅源管理") }
+                text = { AppText("订阅源管理") }
             )
             PillDivider()
             RoundDropdownMenuItem(
                 leadingIcon = { MenuItemIcon(Icons.Default.Group) },
-                text = { Text(stringResource(R.string.all)) },
+                text = { AppText(stringResource(R.string.all)) },
                 onClick = {
                     viewModel.setGroup("")
                     dismiss()
@@ -149,7 +150,7 @@ fun RssScreen(
             uiState.groups.forEach { group ->
                 RoundDropdownMenuItem(
                     leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) },
-                    text = { Text(group) },
+                    text = { AppText(group) },
                     onClick = {
                         viewModel.setGroup(group)
                         dismiss()
@@ -188,8 +189,8 @@ fun RssScreen(
     sourceToDelete?.let { source ->
         AlertDialog(
             onDismissRequest = { sourceToDelete = null },
-            title = { Text(stringResource(R.string.draw)) },
-            text = { Text(stringResource(R.string.sure_del) + "\n" + source.sourceName) },
+            title = { AppText(stringResource(R.string.draw)) },
+            text = { AppText(stringResource(R.string.sure_del) + "\n" + source.sourceName) },
             confirmButton = {
                 TextButton(
                     onClick = {
@@ -197,12 +198,12 @@ fun RssScreen(
                         sourceToDelete = null
                     }
                 ) {
-                    Text(stringResource(R.string.yes))
+                    AppText(stringResource(R.string.yes))
                 }
             },
             dismissButton = {
                 TextButton(onClick = { sourceToDelete = null }) {
-                    Text(stringResource(R.string.no))
+                    AppText(stringResource(R.string.no))
                 }
             }
         )
@@ -246,7 +247,7 @@ fun RssSourceGridItem(
                 PillHeaderDivider(title = source.sourceName)
                 RoundDropdownMenuItem(
                     leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) },
-                    text = { Text(stringResource(R.string.to_top)) },
+                    text = { AppText(stringResource(R.string.to_top)) },
                     onClick = {
                         onTop()
                         showMenu = false
@@ -254,7 +255,7 @@ fun RssSourceGridItem(
                 )
                 RoundDropdownMenuItem(
                     leadingIcon = { MenuItemIcon(Icons.Default.Edit) },
-                    text = { Text(stringResource(R.string.edit)) },
+                    text = { AppText(stringResource(R.string.edit)) },
                     onClick = {
                         onEdit()
                         showMenu = false
@@ -263,7 +264,7 @@ fun RssSourceGridItem(
                 if (!source.loginUrl.isNullOrBlank()) {
                     RoundDropdownMenuItem(
                         leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) },
-                        text = { Text(stringResource(R.string.login)) },
+                        text = { AppText(stringResource(R.string.login)) },
                         onClick = {
                             onLogin()
                             showMenu = false
@@ -272,7 +273,7 @@ fun RssSourceGridItem(
                 }
                 RoundDropdownMenuItem(
                     leadingIcon = { MenuItemIcon(Icons.Default.Close) },
-                    text = { Text(stringResource(R.string.disable_source)) },
+                    text = { AppText(stringResource(R.string.disable_source)) },
                     onClick = {
                         onDisable()
                         showMenu = false
@@ -286,7 +287,7 @@ fun RssSourceGridItem(
                         )
                     },
                     text = {
-                        Text(
+                        AppText(
                             stringResource(R.string.delete),
                             color = MaterialTheme.colorScheme.error
                         )
@@ -299,9 +300,9 @@ fun RssSourceGridItem(
             }
         }
         Spacer(modifier = Modifier.height(8.dp))
-        Text(
+        AppText(
             text = source.sourceName,
-            style = MaterialTheme.typography.labelMedium,
+            style = LegadoTheme.typography.labelMedium,
             maxLines = 2,
             overflow = TextOverflow.Ellipsis,
             textAlign = TextAlign.Center,

+ 27 - 49
app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt

@@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.lazy.rememberLazyListState
@@ -26,14 +25,10 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.FloatingActionButton
 import androidx.compose.material3.Icon
 import androidx.compose.material3.LoadingIndicator
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.PlainTooltip
-import androidx.compose.material3.PrimaryScrollableTabRow
 import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.SnackbarResult
-import androidx.compose.material3.Tab
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TooltipAnchorPosition
 import androidx.compose.material3.TooltipBox
@@ -50,20 +45,19 @@ import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.hapticfeedback.HapticFeedbackType
 import androidx.compose.ui.platform.ClipEntry
 import androidx.compose.ui.platform.LocalClipboard
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalHapticFeedback
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.Dialog
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import io.legado.app.R
 import io.legado.app.base.BaseRuleEvent
 import io.legado.app.data.entities.ReplaceRule
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.ActionItem
 import io.legado.app.ui.widget.components.DraggableSelectionHandler
 import io.legado.app.ui.widget.components.GroupManageBottomSheet
@@ -76,6 +70,8 @@ import io.legado.app.ui.widget.components.importComponents.SourceInputDialog
 import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.rules.RuleListScaffold
+import io.legado.app.ui.widget.components.tabRow.AdaptiveTabRow
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
 import sh.calvin.reorderable.rememberReorderableLazyListState
@@ -207,9 +203,9 @@ fun ReplaceRuleScreen(
             topBarActions = {},
             itemContent = { rule, _ ->
                 Column {
-                    Text(rule.name, style = MaterialTheme.typography.titleMedium)
+                    AppText(rule.name, style = LegadoTheme.typography.titleMedium)
                     if (!rule.group.isNullOrBlank()) {
-                        Text(rule.group!!, style = MaterialTheme.typography.bodySmall)
+                        AppText(rule.group!!, style = LegadoTheme.typography.bodySmall)
                     }
                 }
             }
@@ -279,16 +275,16 @@ fun ReplaceRuleScreen(
     showDeleteRuleDialog?.let { rule ->
         AlertDialog(
             onDismissRequest = { showDeleteRuleDialog = null },
-            title = { Text(stringResource(R.string.delete)) },
-            text = { Text(stringResource(R.string.del_msg)) },
+            title = { AppText(stringResource(R.string.delete)) },
+            text = { AppText(stringResource(R.string.del_msg)) },
             confirmButton = {
                 OutlinedButton(onClick = {
                     viewModel.delete(rule); showDeleteRuleDialog = null
-                }) { Text(stringResource(R.string.ok)) }
+                }) { AppText(stringResource(R.string.ok)) }
             },
             dismissButton = {
                 TextButton(onClick = { showDeleteRuleDialog = null }) {
-                    Text(
+                    AppText(
                         stringResource(R.string.cancel)
                     )
                 }
@@ -347,39 +343,21 @@ fun ReplaceRuleScreen(
         },
         bottomContent = {
             if (tabItems.size > 1) {
-                PrimaryScrollableTabRow(
-                    selectedTabIndex = selectedTabIndex.coerceAtMost(tabItems.size - 1)
-                        .coerceAtLeast(0),
-                    edgePadding = 0.dp,
-                    divider = {},
-                    containerColor = Color.Transparent,
-                ) {
-                    tabItems.forEachIndexed { index, title ->
-                        Tab(
-                            selected = selectedTabIndex == index,
-                            onClick = {
-                                selectedTabIndex = index
-                                viewModel.setGroup(title)
-                            },
-                            text = {
-                                Text(
-                                    text = title,
-                                    maxLines = 1,
-                                    overflow = TextOverflow.Ellipsis,
-                                    modifier = Modifier.padding(horizontal = 16.dp),
-                                    color = MaterialTheme.colorScheme.onSurfaceVariant
-                                )
-                            }
-                        )
+                AdaptiveTabRow(
+                    tabTitles = tabItems,
+                    selectedTabIndex = selectedTabIndex,
+                    onTabSelected = { index ->
+                        selectedTabIndex = index
+                        viewModel.setGroup(tabItems[index])
                     }
-                }
+                )
             }
         },
         floatingActionButton = {
             TooltipBox(
                 positionProvider =
                     TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
-                tooltip = { PlainTooltip { Text("Localized description") } },
+                tooltip = { PlainTooltip { AppText("Localized description") } },
                 state = rememberTooltipState(),
             ) {
                 with(sharedTransitionScope) {
@@ -406,29 +384,29 @@ fun ReplaceRuleScreen(
         snackbarHostState = snackbarHostState,
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.import_str)) },
+                text = { AppText(stringResource(R.string.import_str)) },
                 onClick = { showImportSheet = true; dismiss() },
                 leadingIcon = { Icon(Icons.Default.FileOpen, null) }
             )
             RoundDropdownMenuItem(
-                text = { Text("分组管理") },
+                text = { AppText("分组管理") },
                 onClick = { showGroupManageSheet = true; dismiss() }
             )
             RoundDropdownMenuItem(
-                text = { Text("帮助") },
+                text = { AppText("帮助") },
                 onClick = { /*TODO*/ dismiss() }
             )
             PillDivider()
             RoundDropdownMenuItem(
-                text = { Text("旧的在前") },
+                text = { AppText("旧的在前") },
                 onClick = { viewModel.setSortMode("asc"); dismiss() }
             )
             RoundDropdownMenuItem(
-                text = { Text("新的在前") },
+                text = { AppText("新的在前") },
                 onClick = { viewModel.setSortMode("desc"); dismiss() }
             )
             RoundDropdownMenuItem(
-                text = { Text("名称升序") },
+                text = { AppText("名称升序") },
                 onClick = {
                     viewModel.setSortMode("name_asc")
                     dismiss()
@@ -438,7 +416,7 @@ fun ReplaceRuleScreen(
                 }
             )
             RoundDropdownMenuItem(
-                text = { Text("名称降序") },
+                text = { AppText("名称降序") },
                 onClick = {
                     viewModel.setSortMode("name_desc")
                     dismiss()
@@ -496,15 +474,15 @@ fun ReplaceRuleScreen(
                                 ),
                             dropdownContent = { dismiss ->
                                 DropdownMenuItem(
-                                    text = { Text("移至顶部") },
+                                    text = { AppText("移至顶部") },
                                     onClick = { viewModel.toTop(ui.rule); dismiss() }
                                 )
                                 DropdownMenuItem(
-                                    text = { Text("移至底部") },
+                                    text = { AppText("移至底部") },
                                     onClick = { viewModel.toBottom(ui.rule); dismiss() }
                                 )
                                 DropdownMenuItem(
-                                    text = { Text("删除") },
+                                    text = { AppText("删除") },
                                     onClick = { showDeleteRuleDialog = ui.rule; dismiss() }
                                 )
                             }

+ 29 - 29
app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt

@@ -52,7 +52,6 @@ import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.PlainTooltip
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TooltipAnchorPosition
 import androidx.compose.material3.TooltipBox
@@ -78,10 +77,11 @@ import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.button.AlertButton
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
+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 org.koin.androidx.compose.koinViewModel
 
 @Composable
@@ -119,7 +119,7 @@ fun ReplaceEditScreen(
                 .imePadding(),
             topBar = {
                 GlassMediumFlexibleTopAppBar(
-                    title = { Text(if (state.id > 0) "编辑替换规则" else "新增替换规则") },
+                    title = if (state.id > 0) "编辑替换规则" else "新增替换规则",
                     navigationIcon = {
                         TopbarNavigationButton(onClick = onBack)
                     },
@@ -143,14 +143,14 @@ fun ReplaceEditScreen(
                             onDismissRequest = { showMenu = false }
                         ) {
                             DropdownMenuItem(
-                                text = { Text("复制规则") },
+                                text = { AppText("复制规则") },
                                 onClick = {
                                     showMenu = false
                                     viewModel.copyRule()
                                 }
                             )
                             DropdownMenuItem(
-                                text = { Text("粘贴规则") },
+                                text = { AppText("粘贴规则") },
                                 onClick = {
                                     showMenu = false
                                     viewModel.pasteRule(onSuccess = {})
@@ -167,7 +167,7 @@ fun ReplaceEditScreen(
                     positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
                         TooltipAnchorPosition.Above
                     ),
-                    tooltip = { PlainTooltip { Text("添加") } },
+                    tooltip = { PlainTooltip { AppText("添加") } },
                     state = rememberTooltipState(),
                 ) {
                     FloatingActionButton(
@@ -214,7 +214,7 @@ fun ReplaceEditScreen(
                     OutlinedTextField(
                         value = state.name,
                         onValueChange = viewModel::onNameChange,
-                        label = { Text("规则名称") },
+                        label = { AppText("规则名称") },
                         modifier = Modifier
                             .fillMaxWidth()
                             .onFocusChanged {
@@ -234,8 +234,8 @@ fun ReplaceEditScreen(
                     OutlinedTextField(
                         value = state.pattern,
                         onValueChange = viewModel::onPatternChange,
-                        label = { Text("匹配规则") },
-                        placeholder = { Text("输入正则表达式或关键字") },
+                        label = { AppText("匹配规则") },
+                        placeholder = { AppText("输入正则表达式或关键字") },
                         modifier = Modifier
                             .fillMaxWidth()
                             .onFocusChanged {
@@ -247,8 +247,8 @@ fun ReplaceEditScreen(
                     OutlinedTextField(
                         value = state.replacement,
                         onValueChange = viewModel::onReplacementChange,
-                        label = { Text("替换为") },
-                        placeholder = { Text("输入替换内容或捕获组") },
+                        label = { AppText("替换为") },
+                        placeholder = { AppText("输入替换内容或捕获组") },
                         modifier = Modifier
                             .fillMaxWidth()
                             .onFocusChanged {
@@ -265,7 +265,7 @@ fun ReplaceEditScreen(
                         FilterChip(
                             selected = state.scopeTitle,
                             onClick = { viewModel.onScopeTitleChange(!state.scopeTitle) },
-                            label = { Text("标题") },
+                            label = { AppText("标题") },
                             leadingIcon = if (state.scopeTitle) {
                                 {
                                     Icon(
@@ -282,7 +282,7 @@ fun ReplaceEditScreen(
                         FilterChip(
                             selected = state.scopeContent,
                             onClick = { viewModel.onScopeContentChange(!state.scopeContent) },
-                            label = { Text("内容") },
+                            label = { AppText("内容") },
                             leadingIcon = if (state.scopeContent) {
                                 {
                                     Icon(
@@ -299,7 +299,7 @@ fun ReplaceEditScreen(
                         FilterChip(
                             selected = state.isRegex,
                             onClick = { viewModel.onRegexChange(!state.isRegex) },
-                            label = { Text("使用正则") },
+                            label = { AppText("使用正则") },
                             leadingIcon = if (state.isRegex) {
                                 {
                                     Icon(
@@ -316,8 +316,8 @@ fun ReplaceEditScreen(
                     OutlinedTextField(
                         value = state.scope,
                         onValueChange = viewModel::onScopeChange,
-                        label = { Text("特定范围") },
-                        placeholder = { Text("指定规则适用的范围") },
+                        label = { AppText("特定范围") },
+                        placeholder = { AppText("指定规则适用的范围") },
                         modifier = Modifier
                             .fillMaxWidth()
                             .onFocusChanged {
@@ -329,8 +329,8 @@ fun ReplaceEditScreen(
                     OutlinedTextField(
                         value = state.excludeScope,
                         onValueChange = viewModel::onExcludeScopeChange,
-                        label = { Text("排除范围") },
-                        placeholder = { Text("指定规则不适用的范围") },
+                        label = { AppText("排除范围") },
+                        placeholder = { AppText("指定规则不适用的范围") },
                         modifier = Modifier
                             .fillMaxWidth()
                             .onFocusChanged {
@@ -342,8 +342,8 @@ fun ReplaceEditScreen(
                     OutlinedTextField(
                         value = state.timeout,
                         onValueChange = viewModel::onTimeoutChange,
-                        label = { Text("超时 (ms)") },
-                        placeholder = { Text("3000") },
+                        label = { AppText("超时 (ms)") },
+                        placeholder = { AppText("3000") },
                         modifier = Modifier.fillMaxWidth()
                     )
 
@@ -383,8 +383,8 @@ fun GroupSelector(
             OutlinedTextField(
                 value = currentGroup,
                 onValueChange = onGroupChange,
-                label = { Text("分组") },
-                placeholder = { Text("默认") },
+                label = { AppText("分组") },
+                placeholder = { AppText("默认") },
                 trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
                 colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
                 modifier = Modifier
@@ -400,7 +400,7 @@ fun GroupSelector(
             ) {
                 allGroups.forEach { selectionOption ->
                     DropdownMenuItem(
-                        text = { Text(selectionOption) },
+                        text = { AppText(selectionOption) },
                         onClick = {
                             onGroupChange(selectionOption)
                             expanded = false
@@ -426,9 +426,9 @@ fun ManageGroupDialog(
 
     AlertDialog(
         onDismissRequest = onDismiss,
-        title = { Text("分组管理") },
+        title = { AppText("分组管理") },
         text = {
-            if (groups.isEmpty()) Text("暂无其他分组")
+            if (groups.isEmpty()) AppText("暂无其他分组")
             else Column(
                 modifier = Modifier.verticalScroll(rememberScrollState()),
                 verticalArrangement = Arrangement.spacedBy(8.dp)
@@ -448,7 +448,7 @@ fun ManageGroupDialog(
                         verticalAlignment = Alignment.CenterVertically
                     ) {
                         Checkbox(checked = isSelected, onCheckedChange = null)
-                        Text(group, Modifier.padding(start = 8.dp))
+                        AppText(group, Modifier.padding(start = 8.dp))
                     }
                 }
             }
@@ -462,7 +462,7 @@ fun ManageGroupDialog(
                 text = "删除选中"
             )
         },
-        dismissButton = { TextButton(onClick = onDismiss) { Text("关闭") } }
+        dismissButton = { TextButton(onClick = onDismiss) { AppText("关闭") } }
     )
 }
 
@@ -482,7 +482,7 @@ fun QuickInputBar(
         symbols.forEach { symbol ->
             AssistChip(
                 onClick = { onInsert(symbol) },
-                label = { Text(symbol) },
+                label = { AppText(symbol) },
                 modifier = Modifier.padding(end = 8.dp)
             )
         }

+ 7 - 7
app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt

@@ -19,7 +19,6 @@ import androidx.compose.material.icons.filled.Group
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.SnackbarHostState
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
@@ -45,6 +44,7 @@ import io.legado.app.ui.widget.components.dialog.TextListInputDialog
 import io.legado.app.ui.widget.components.divider.PillDivider
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.rules.RuleListScaffold
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.startActivity
 
 @OptIn(ExperimentalMaterial3Api::class)
@@ -133,7 +133,7 @@ fun RssFavoritesScreen(
                     Row(verticalAlignment = Alignment.CenterVertically) {
                         Icon(Icons.Default.Group, null, modifier = Modifier.size(18.dp))
                         Spacer(Modifier.width(12.dp))
-                        Text(stringResource(R.string.all))
+                        AppText(stringResource(R.string.all))
                     }
                 },
                 onClick = {
@@ -151,7 +151,7 @@ fun RssFavoritesScreen(
                                 modifier = Modifier.size(18.dp)
                             )
                             Spacer(Modifier.width(12.dp))
-                            Text(group)
+                            AppText(group)
                         }
                     },
                     onClick = {
@@ -166,7 +166,7 @@ fun RssFavoritesScreen(
                     Row(verticalAlignment = Alignment.CenterVertically) {
                         Icon(Icons.Default.DeleteSweep, null, modifier = Modifier.size(18.dp))
                         Spacer(Modifier.width(12.dp))
-                        Text(stringResource(R.string.delete_select_group))
+                        AppText(stringResource(R.string.delete_select_group))
                     }
                 },
                 onClick = {
@@ -179,7 +179,7 @@ fun RssFavoritesScreen(
                     Row(verticalAlignment = Alignment.CenterVertically) {
                         Icon(Icons.Default.DeleteForever, null, modifier = Modifier.size(18.dp))
                         Spacer(Modifier.width(12.dp))
-                        Text(stringResource(R.string.all))
+                        AppText(stringResource(R.string.all))
                     }
                 },
                 onClick = {
@@ -248,14 +248,14 @@ fun RssFavoritesScreen(
                         },
                         dropdownContent = { dismiss ->
                             RoundDropdownMenuItem(
-                                text = { Text(stringResource(R.string.change_group)) },
+                                text = { AppText(stringResource(R.string.change_group)) },
                                 onClick = {
                                     showSetGroupDialog = rssStar
                                     dismiss()
                                 }
                             )
                             RoundDropdownMenuItem(
-                                text = { Text(stringResource(R.string.delete)) },
+                                text = { AppText(stringResource(R.string.delete)) },
                                 onClick = {
                                     viewModel.deleteStar(rssStar)
                                     dismiss()

+ 23 - 19
app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt

@@ -17,11 +17,9 @@ import androidx.compose.material.icons.filled.Delete
 import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.SnackbarResult
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -43,6 +41,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import io.legado.app.R
 import io.legado.app.base.BaseRuleEvent
 import io.legado.app.data.entities.RssSource
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.ActionItem
 import io.legado.app.ui.widget.components.DraggableSelectionHandler
 import io.legado.app.ui.widget.components.GroupManageBottomSheet
@@ -58,6 +57,7 @@ import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.rules.RuleListScaffold
+import io.legado.app.ui.widget.components.text.AppText
 import org.koin.androidx.compose.koinViewModel
 import sh.calvin.reorderable.rememberReorderableLazyListState
 
@@ -209,8 +209,12 @@ fun RssSourceScreen(
             onConfirm = { viewModel.saveImportedRules() },
             itemContent = { source, _ ->
                 Column {
-                    Text(source.sourceName, style = MaterialTheme.typography.titleMedium)
-                    Text(source.sourceUrl, style = MaterialTheme.typography.bodySmall, maxLines = 1)
+                    AppText(source.sourceName, style = LegadoTheme.typography.titleMedium)
+                    AppText(
+                        source.sourceUrl,
+                        style = LegadoTheme.typography.bodySmall,
+                        maxLines = 1
+                    )
                 }
             }
         )
@@ -225,16 +229,16 @@ fun RssSourceScreen(
     showDeleteRuleDialog?.let { source ->
         AlertDialog(
             onDismissRequest = { showDeleteRuleDialog = null },
-            title = { Text(stringResource(R.string.delete)) },
-            text = { Text(stringResource(R.string.del_msg)) },
+            title = { AppText(stringResource(R.string.delete)) },
+            text = { AppText(stringResource(R.string.del_msg)) },
             confirmButton = {
                 OutlinedButton(onClick = {
                     viewModel.del(source); showDeleteRuleDialog = null
-                }) { Text(stringResource(R.string.ok)) }
+                }) { AppText(stringResource(R.string.ok)) }
             },
             dismissButton = {
                 TextButton(onClick = { showDeleteRuleDialog = null }) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
             }
         )
@@ -287,11 +291,11 @@ fun RssSourceScreen(
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
                 onClick = { showGroupManageSheet = true },
-                text = { Text("分组管理") },
+                text = { AppText("分组管理") },
             )
             Box {
                 RoundDropdownMenuItem(
-                    text = { Text(stringResource(R.string.import_rss_source)) },
+                    text = { AppText(stringResource(R.string.import_rss_source)) },
                     onClick = { showImportMenu = true }
                 )
                 RoundDropdownMenu(
@@ -299,7 +303,7 @@ fun RssSourceScreen(
                     onDismissRequest = { showImportMenu = false }
                 ) {
                     RoundDropdownMenuItem(
-                        text = { Text(stringResource(R.string.import_on_line)) },
+                        text = { AppText(stringResource(R.string.import_on_line)) },
                         onClick = {
                             showImportMenu = false
                             dismiss()
@@ -307,7 +311,7 @@ fun RssSourceScreen(
                         }
                     )
                     RoundDropdownMenuItem(
-                        text = { Text(stringResource(R.string.import_local)) },
+                        text = { AppText(stringResource(R.string.import_local)) },
                         onClick = {
                             showImportMenu = false
                             dismiss()
@@ -315,7 +319,7 @@ fun RssSourceScreen(
                         }
                     )
                     RoundDropdownMenuItem(
-                        text = { Text(stringResource(R.string.import_default_rule)) },
+                        text = { AppText(stringResource(R.string.import_default_rule)) },
                         onClick = {
                             showImportMenu = false
                             dismiss()
@@ -326,29 +330,29 @@ fun RssSourceScreen(
             }
             PillDivider()
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.all)) },
+                text = { AppText(stringResource(R.string.all)) },
                 onClick = { dismiss(); viewModel.setGroupFilter(null) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.enabled)) },
+                text = { AppText(stringResource(R.string.enabled)) },
                 onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_ENABLED) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.disabled)) },
+                text = { AppText(stringResource(R.string.disabled)) },
                 onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_DISABLED) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.need_login)) },
+                text = { AppText(stringResource(R.string.need_login)) },
                 onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_LOGIN) }
             )
             RoundDropdownMenuItem(
-                text = { Text(stringResource(R.string.no_group)) },
+                text = { AppText(stringResource(R.string.no_group)) },
                 onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_NO_GROUP) }
             )
             PillDivider()
             groups.forEach { group ->
                 RoundDropdownMenuItem(
-                    text = { Text(group) },
+                    text = { AppText(group) },
                     onClick = { dismiss(); viewModel.setGroupFilter("${RssSourceViewModel.PREFIX_GROUP}$group") }
                 )
             }

+ 12 - 12
app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt

@@ -22,11 +22,9 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.FloatingActionButton
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.PlainTooltip
 import androidx.compose.material3.SnackbarHostState
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TooltipAnchorPosition
 import androidx.compose.material3.TooltipBox
@@ -54,12 +52,14 @@ import io.legado.app.data.entities.RuleSubType
 import io.legado.app.ui.association.ImportBookSourceDialog
 import io.legado.app.ui.association.ImportReplaceRuleDialog
 import io.legado.app.ui.association.ImportRssSourceDialog
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.EmptyMessageView
 import io.legado.app.ui.widget.components.card.SelectionItemCard
 import io.legado.app.ui.widget.components.checkBox.CheckboxGroupContainer
 import io.legado.app.ui.widget.components.checkBox.CheckboxItem
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.rules.RuleListScaffold
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.utils.showDialogFragment
 import io.legado.app.utils.toastOnUi
 
@@ -93,7 +93,7 @@ fun RuleSubScreen(
                     Row(verticalAlignment = Alignment.CenterVertically) {
                         Icon(Icons.AutoMirrored.Filled.Sort, null, modifier = Modifier.size(18.dp))
                         Spacer(Modifier.size(12.dp))
-                        Text(stringResource(R.string.sort))
+                        AppText(stringResource(R.string.sort))
                     }
                 },
                 onClick = {
@@ -106,7 +106,7 @@ fun RuleSubScreen(
             TooltipBox(
                 positionProvider =
                     TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
-                tooltip = { PlainTooltip { Text("Localized description") } },
+                tooltip = { PlainTooltip { AppText("Localized description") } },
                 state = rememberTooltipState(),
             ) {
                 FloatingActionButton(
@@ -185,7 +185,7 @@ fun RuleSubScreen(
                         },
                         dropdownContent = { dismiss ->
                             RoundDropdownMenuItem(
-                                text = { Text(stringResource(R.string.delete)) },
+                                text = { AppText(stringResource(R.string.delete)) },
                                 onClick = {
                                     viewModel.delete(ruleSub)
                                     dismiss()
@@ -226,24 +226,24 @@ fun RuleSubEditDialog(
 
     AlertDialog(
         onDismissRequest = onDismiss,
-        title = { Text(stringResource(R.string.rule_subscription)) },
+        title = { AppText(stringResource(R.string.rule_subscription)) },
         text = {
             Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                 OutlinedTextField(
                     value = name,
                     onValueChange = { name = it },
-                    label = { Text(stringResource(R.string.name)) },
+                    label = { AppText(stringResource(R.string.name)) },
                     modifier = Modifier.fillMaxWidth()
                 )
                 OutlinedTextField(
                     value = url,
                     onValueChange = { url = it },
-                    label = { Text("URL") },
+                    label = { AppText("URL") },
                     modifier = Modifier.fillMaxWidth()
                 )
-                Text(
+                AppText(
                     text = "订阅类型",
-                    style = MaterialTheme.typography.titleSmall,
+                    style = LegadoTheme.typography.titleSmall,
                     modifier = Modifier.padding(top = 8.dp)
                 )
                 CheckboxGroupContainer(columns = 2) {
@@ -265,12 +265,12 @@ fun RuleSubEditDialog(
             TextButton(onClick = {
                 onConfirm(ruleSub.copy(name = name, url = url, type = type))
             }) {
-                Text(stringResource(R.string.ok))
+                AppText(stringResource(R.string.ok))
             }
         },
         dismissButton = {
             TextButton(onClick = onDismiss) {
-                Text(stringResource(R.string.cancel))
+                AppText(stringResource(R.string.cancel))
             }
         }
     )

+ 19 - 0
app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt

@@ -0,0 +1,19 @@
+package io.legado.app.ui.theme
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+
+@Composable
+fun Modifier.adaptiveHorizontalPadding(): Modifier {
+    val horizontal = if (ThemeResolver.isMiuixEngine(composeEngine)) 12.dp else 16.dp
+    return this.padding(horizontal = horizontal)
+}
+
+@Composable
+fun Modifier.adaptiveVerticalPadding(): Modifier {
+    val horizontal = if (ThemeResolver.isMiuixEngine(composeEngine)) 12.dp else 8.dp
+    return this.padding(horizontal = horizontal)
+}

+ 67 - 10
app/src/main/java/io/legado/app/ui/theme/AppTheme.kt

@@ -7,9 +7,13 @@ import androidx.compose.material3.MotionScheme
 import androidx.compose.material3.Shapes
 import androidx.compose.material3.Typography
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.remember
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.LocalContext
 import io.legado.app.ui.config.themeConfig.ThemeConfig
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.theme.ThemeController
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -20,29 +24,82 @@ fun AppTheme(
     val context = LocalContext.current
     val appThemeMode = ThemeResolver.resolveThemeMode(ThemeConfig.appTheme)
     val isPureBlack = ThemeConfig.isPureBlack
-    val paletteStyle = ThemeConfig.paletteStyle
+    val paletteStyleStr = ThemeConfig.paletteStyle
     val materialVersion = ThemeConfig.materialVersion
+    val composeEngine = ThemeConfig.composeEngine
+    val colorSchemeMode = ThemeResolver.resolveColorSchemeMode(ThemeConfig.themeMode)
+    val paletteStyle =
+        remember(paletteStyleStr) { ThemeResolver.resolvePaletteStyle(paletteStyleStr) }
+    val seedColor = remember(ThemeConfig.cPrimary) {
+        if (ThemeConfig.cPrimary != 0) Color(ThemeConfig.cPrimary) else Color(0xFF3482FF)
+    }
 
     val colorScheme =
-        remember(context, appThemeMode, darkTheme, isPureBlack, paletteStyle, materialVersion) {
+        remember(context, appThemeMode, darkTheme, isPureBlack, paletteStyleStr, materialVersion) {
             ThemeManager.getColorScheme(
                 context = context,
                 mode = appThemeMode,
                 darkTheme = darkTheme,
                 isAmoled = isPureBlack,
-                paletteStyle = paletteStyle,
+                paletteStyle = paletteStyleStr,
                 materialVersion = materialVersion
             )
         }
 
-    MaterialExpressiveTheme(
-        colorScheme = colorScheme,
-        typography = Typography(),
-        motionScheme = MotionScheme.expressive(),
-        shapes = Shapes()
+    val themeColors = remember(colorScheme, darkTheme, seedColor, paletteStyle, colorSchemeMode) {
+        LegadoThemeColors(
+            colorScheme = colorScheme,
+            isDark = darkTheme,
+            seedColor = seedColor,
+            paletteStyle = paletteStyle,
+            themeMode = colorSchemeMode,
+            useDynamicColor = appThemeMode == AppThemeMode.Dynamic,
+            composeEngine = composeEngine
+        )
+    }
+
+    CompositionLocalProvider(
+        LocalLegadoThemeColors provides themeColors
     ) {
-        AppBackground(darkTheme = darkTheme) {
-            content()
+        when {
+            ThemeResolver.isMiuixEngine(themeColors.composeEngine) -> {
+                val controller = remember(colorSchemeMode, darkTheme) {
+                    ThemeController(
+                        colorSchemeMode = colorSchemeMode,
+                        isDark = darkTheme
+                    )
+                }
+
+                MiuixTheme(
+                    controller = controller
+                ) {
+                    val miuixTextStyles = MiuixTheme.textStyles
+                    val mappedTypography = remember(miuixTextStyles) {
+                        miuixStylesToM3Typography(miuixTextStyles)
+                    }
+
+                    CompositionLocalProvider(
+                        LocalLegadoTypography provides mappedTypography
+                    ) {
+                        AppBackground(darkTheme = darkTheme) {
+                            content()
+                        }
+                    }
+                }
+            }
+
+            else -> {
+                MaterialExpressiveTheme(
+                    colorScheme = colorScheme,
+                    typography = Typography(),
+                    motionScheme = MotionScheme.expressive(),
+                    shapes = Shapes()
+                ) {
+                    AppBackground(darkTheme = darkTheme) {
+                        content()
+                    }
+                }
+            }
         }
     }
 }

+ 4 - 4
app/src/main/java/io/legado/app/ui/theme/HazeStyle.kt

@@ -7,8 +7,8 @@ import dev.chrisbanes.haze.HazeState
 import dev.chrisbanes.haze.hazeEffect
 import dev.chrisbanes.haze.hazeSource
 import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
-import dev.chrisbanes.haze.materials.HazeMaterials
 import io.legado.app.ui.config.themeConfig.ThemeConfig
+import io.legado.app.ui.theme.hazeStyle.HazeLegado
 
 /**
  * 自动感知全局配置的 HazeSource
@@ -31,9 +31,9 @@ fun Modifier.responsiveHazeEffect(
     if (!enableBlur) return this
 
     val style = if (enableProgressiveBlur) {
-        HazeMaterials.ultraThin()
+        HazeLegado.ultraThin()
     } else {
-        HazeMaterials.regular()
+        HazeLegado.regular()
     }
 
     return this.hazeEffect(
@@ -61,6 +61,6 @@ fun Modifier.regularHazeEffect(state: HazeState): Modifier {
 
     return this.hazeEffect(
         state = state,
-        style = HazeMaterials.ultraThin()
+        style = HazeLegado.ultraThin()
     )
 }

+ 85 - 0
app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt

@@ -0,0 +1,85 @@
+package io.legado.app.ui.theme
+
+import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.Typography
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.runtime.compositionLocalOf
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.graphics.Color
+import com.materialkolor.PaletteStyle
+import dev.chrisbanes.haze.HazeState
+import top.yukonga.miuix.kmp.theme.ColorSchemeMode
+
+data class LegadoThemeColors(
+    val colorScheme: ColorScheme,
+    val isDark: Boolean,
+    val seedColor: Color,
+    val paletteStyle: PaletteStyle,
+    val themeMode: ColorSchemeMode,
+    val useDynamicColor: Boolean,
+    val composeEngine: String,
+)
+
+val LocalLegadoThemeColors = staticCompositionLocalOf {
+    LegadoThemeColors(
+        colorScheme = lightColorScheme(),
+        isDark = false,
+        seedColor = Color.Unspecified,
+        paletteStyle = PaletteStyle.TonalSpot,
+        themeMode = ColorSchemeMode.System,
+        useDynamicColor = true,
+        composeEngine = "m3"
+    )
+}
+
+val LocalLegadoTypography = staticCompositionLocalOf {
+    Typography()
+}
+
+val LocalHazeState = compositionLocalOf<HazeState?> { null }
+
+object LegadoTheme {
+
+    val colorScheme: ColorScheme
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoThemeColors.current.colorScheme
+
+    val isDark: Boolean
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoThemeColors.current.isDark
+
+    val seedColor: Color
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoThemeColors.current.seedColor
+
+    val paletteStyle: PaletteStyle
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoThemeColors.current.paletteStyle
+
+    val themeMode: ColorSchemeMode
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoThemeColors.current.themeMode
+
+    val composeEngine: String
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoThemeColors.current.composeEngine
+
+    val useDynamicColor: Boolean
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoThemeColors.current.useDynamicColor
+
+    val typography: Typography
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalLegadoTypography.current
+
+}

+ 12 - 0
app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt

@@ -4,6 +4,7 @@ import com.materialkolor.Contrast
 import com.materialkolor.PaletteStyle
 import com.materialkolor.dynamiccolor.ColorSpec
 import io.legado.app.ui.config.themeConfig.ThemeConfig
+import top.yukonga.miuix.kmp.theme.ColorSchemeMode
 
 object ThemeResolver {
 
@@ -48,6 +49,17 @@ object ThemeResolver {
         }
     }
 
+    fun resolveColorSchemeMode(value: String): ColorSchemeMode = when (value) {
+        "0" -> ColorSchemeMode.System
+        "1" -> ColorSchemeMode.Light
+        "2" -> ColorSchemeMode.Dark
+        else -> ColorSchemeMode.System
+    }
+
+    fun isMiuixEngine(composeEngine: String): Boolean = composeEngine == "miuix"
+
+    fun isM3Engine(composeEngine: String): Boolean = composeEngine == "m3"
+
     fun resolveColorSpecVersion(colorSpec: ThemeColorSpec): ColorSpec.SpecVersion {
         return when (colorSpec) {
             ThemeColorSpec.SPEC_2025 -> ColorSpec.SpecVersion.SPEC_2025

+ 44 - 0
app/src/main/java/io/legado/app/ui/theme/Typography.kt

@@ -0,0 +1,44 @@
+package io.legado.app.ui.theme
+
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.font.FontWeight
+import top.yukonga.miuix.kmp.theme.TextStyles
+
+
+/**
+ * 将 Miuix 的 TextStyles 语义化映射为 Material 3 的 Typography
+ */
+
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
+fun miuixStylesToM3Typography(miuixStyles: TextStyles): Typography {
+    return Typography(
+        displayLarge = miuixStyles.title1,   // 32.sp
+        displayMedium = miuixStyles.title2,  // 24.sp
+        displaySmall = miuixStyles.title3,   // 20.sp
+
+        headlineLarge = miuixStyles.title2,  // 24.sp
+        headlineMedium = miuixStyles.title3, // 20.sp
+        headlineSmall = miuixStyles.title4,  // 18.sp
+
+        titleLarge = miuixStyles.headline1,  // 17.sp
+        titleMedium = miuixStyles.headline2, // 16.sp
+        titleSmall = miuixStyles.subtitle,   // 14.sp, Bold
+
+        bodyLarge = miuixStyles.paragraph,   // 17.sp, lineHeight 1.2em (如果不需要行高也可以换成 main)
+        bodyMedium = miuixStyles.body1,      // 16.sp
+        bodySmall = miuixStyles.body2,       // 14.sp
+
+        labelLarge = miuixStyles.button,     // 17.sp
+        labelMedium = miuixStyles.footnote1, // 13.sp
+        labelSmall = miuixStyles.footnote2,   // 11.sp
+
+        bodyLargeEmphasized = miuixStyles.paragraph.copy(fontWeight = FontWeight.Medium),
+        bodyMediumEmphasized = miuixStyles.body1.copy(fontWeight = FontWeight.Medium),
+        bodySmallEmphasized = miuixStyles.body2.copy(fontWeight = FontWeight.Medium),
+
+        labelLargeEmphasized = miuixStyles.button.copy(fontWeight = FontWeight.Medium),
+        labelMediumEmphasized = miuixStyles.footnote1.copy(fontWeight = FontWeight.Medium),
+        labelSmallEmphasized = miuixStyles.footnote2.copy(fontWeight = FontWeight.Medium)
+    )
+}

+ 48 - 0
app/src/main/java/io/legado/app/ui/theme/hazeStyle/HazeLegado.kt

@@ -0,0 +1,48 @@
+package io.legado.app.ui.theme.hazeStyle
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.unit.dp
+import dev.chrisbanes.haze.HazeStyle
+import dev.chrisbanes.haze.HazeTint
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+
+object HazeLegado {
+
+    @Composable
+    @ReadOnlyComposable
+    fun ultraThin(
+        containerColor: Color = if (ThemeResolver.isMiuixEngine(composeEngine)) MiuixTheme.colorScheme.surface else MaterialTheme.colorScheme.surface,
+    ): HazeStyle = hazeLegado(
+        containerColor = containerColor,
+        lightAlpha = 0.35f,
+        darkAlpha = 0.55f,
+    )
+
+    @Composable
+    @ReadOnlyComposable
+    fun regular(
+        containerColor: Color = if (ThemeResolver.isMiuixEngine(composeEngine)) MiuixTheme.colorScheme.surface else MaterialTheme.colorScheme.surface,
+    ): HazeStyle = hazeLegado(
+        containerColor = containerColor,
+        lightAlpha = 0.73f,
+        darkAlpha = 0.8f,
+    )
+
+    private fun hazeLegado(
+        containerColor: Color,
+        lightAlpha: Float,
+        darkAlpha: Float,
+    ): HazeStyle = HazeStyle(
+        blurRadius = 24.dp,
+        backgroundColor = containerColor,
+        tint = HazeTint(
+            containerColor.copy(alpha = if (containerColor.luminance() >= 0.5) lightAlpha else darkAlpha),
+        ),
+    )
+}

+ 6 - 5
app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt

@@ -13,7 +13,6 @@ import androidx.compose.material3.CardDefaults
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
@@ -22,6 +21,8 @@ import androidx.compose.ui.draw.rotate
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -54,9 +55,9 @@ fun CollapsibleHeader(
                 if (titleContent != null) {
                     titleContent()
                 } else {
-                    Text(
+                    AppText(
                         text = title,
-                        style = MaterialTheme.typography.bodySmallEmphasized.copy(
+                        style = LegadoTheme.typography.bodySmallEmphasized.copy(
                             fontWeight = FontWeight.Bold,
                             color = MaterialTheme.colorScheme.primary
                         ),
@@ -64,9 +65,9 @@ fun CollapsibleHeader(
                         overflow = TextOverflow.Ellipsis
                     )
                     subtitle?.let {
-                        Text(
+                        AppText(
                             text = it,
-                            style = MaterialTheme.typography.labelSmallEmphasized.copy(
+                            style = LegadoTheme.typography.labelSmallEmphasized.copy(
                                 color = MaterialTheme.colorScheme.onSurfaceVariant
                             ),
                             maxLines = 1,

+ 3 - 3
app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt

@@ -9,7 +9,6 @@ import androidx.compose.animation.togetherWith
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
 import androidx.compose.material3.LocalTextStyle
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -23,6 +22,7 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.TextUnit
+import io.legado.app.ui.widget.components.text.AppText
 
 @Composable
 fun AnimatedText(
@@ -60,7 +60,7 @@ fun AnimatedText(
                     },
                     label = ""
                 ) {
-                    Text(
+                    AppText(
                         style = style,
                         color = color,
                         softWrap = softWrap,
@@ -117,7 +117,7 @@ fun AnimatedTextLine(
         label = "LineAnimation",
         modifier = modifier
     ) { targetText ->
-        Text(
+        AppText(
             text = targetText,
             modifier = modifier,
             style = style,

+ 56 - 0
app/src/main/java/io/legado/app/ui/widget/components/AppFloatingActionButton.kt

@@ -0,0 +1,56 @@
+package io.legado.app.ui.widget.components
+
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FloatingActionButton
+import androidx.compose.material3.PlainTooltip
+import androidx.compose.material3.TooltipAnchorPosition
+import androidx.compose.material3.TooltipBox
+import androidx.compose.material3.TooltipDefaults
+import androidx.compose.material3.rememberTooltipState
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.text.AppText
+import top.yukonga.miuix.kmp.basic.FloatingActionButton as MiuixFloatingActionButton
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AppFloatingActionButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    tooltipText: String? = null,
+    content: @Composable () -> Unit
+) {
+    val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)
+
+    if (isMiuix) {
+        MiuixFloatingActionButton(
+            onClick = onClick,
+            modifier = modifier,
+            content = content
+        )
+    } else {
+        if (tooltipText != null) {
+            TooltipBox(
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
+                    TooltipAnchorPosition.Above
+                ),
+                tooltip = { PlainTooltip { AppText(tooltipText) } },
+                state = rememberTooltipState(),
+            ) {
+                FloatingActionButton(
+                    onClick = onClick,
+                    modifier = modifier,
+                    content = content
+                )
+            }
+        } else {
+            FloatingActionButton(
+                onClick = onClick,
+                modifier = modifier,
+                content = content
+            )
+        }
+    }
+}

+ 93 - 0
app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt

@@ -0,0 +1,93 @@
+package io.legado.app.ui.widget.components
+
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.material3.BottomAppBarDefaults
+import androidx.compose.material3.NavigationBar
+import androidx.compose.material3.NavigationBarItem
+import androidx.compose.material3.NavigationBarItemDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import io.legado.app.ui.config.themeConfig.ThemeConfig
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.text.AppText
+import top.yukonga.miuix.kmp.basic.NavigationBarDisplayMode
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.basic.NavigationBar as MiuixNavigationBar
+import top.yukonga.miuix.kmp.basic.NavigationBarItem as MiuixNavigationBarItem
+
+@Composable
+fun AppNavigationBar(
+    modifier: Modifier = Modifier,
+    miuixMode: NavigationBarDisplayMode = NavigationBarDisplayMode.IconAndText,
+    content: @Composable RowScope.() -> Unit
+) {
+    val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)
+    val opacity = (ThemeConfig.bottomBarOpacity.coerceIn(0, 100)) / 100f
+
+    if (isMiuix) {
+        val baseColor = GlassDefaults.glassColor(
+            noBlurColor = MiuixTheme.colorScheme.surface,
+            blurAlpha = GlassDefaults.DefaultBlurAlpha
+        )
+        val finalColor = baseColor.copy(alpha = (baseColor.alpha * opacity).coerceIn(0f, 1f))
+
+        MiuixNavigationBar(
+            modifier = modifier,
+            color = finalColor,
+            mode = miuixMode,
+            content = content
+        )
+    } else {
+        val baseColor = GlassDefaults.glassColor(
+            noBlurColor = BottomAppBarDefaults.containerColor,
+            blurAlpha = GlassDefaults.DefaultBlurAlpha
+        )
+        val finalColor = baseColor.copy(alpha = (baseColor.alpha * opacity).coerceIn(0f, 1f))
+
+        NavigationBar(
+            modifier = modifier,
+            containerColor = finalColor,
+            content = content
+        )
+    }
+}
+
+@Composable
+fun RowScope.AppNavigationBarItem(
+    selected: Boolean,
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    labelString: String,
+    miuixIcon: ImageVector,
+    m3Icon: @Composable () -> Unit,
+    m3IndicatorColor: Color,
+    m3ShowLabel: Boolean,
+    m3AlwaysShowLabel: Boolean,
+) {
+    val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)
+
+    if (isMiuix) {
+        MiuixNavigationBarItem(
+            selected = selected,
+            onClick = onClick,
+            icon = miuixIcon,
+            label = labelString,
+            modifier = modifier
+        )
+    } else {
+        NavigationBarItem(
+            selected = selected,
+            onClick = onClick,
+            modifier = modifier,
+            icon = m3Icon,
+            colors = NavigationBarItemDefaults.colors(indicatorColor = m3IndicatorColor),
+            label = if (m3ShowLabel) {
+                { AppText(labelString) }
+            } else null,
+            alwaysShowLabel = m3AlwaysShowLabel
+        )
+    }
+}

+ 67 - 44
app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt

@@ -3,7 +3,6 @@ package io.legado.app.ui.widget.components
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.RowScope
 import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material3.ExperimentalMaterial3Api
@@ -11,29 +10,27 @@ import androidx.compose.material3.FabPosition
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Scaffold
 import androidx.compose.material3.ScaffoldDefaults
-import androidx.compose.material3.TopAppBarColors
-import androidx.compose.material3.TopAppBarScrollBehavior
 import androidx.compose.material3.contentColorFor
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import dev.chrisbanes.haze.HazeState
 import io.legado.app.ui.config.themeConfig.ThemeConfig
-import io.legado.app.ui.theme.responsiveHazeEffect
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.LocalHazeState
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.theme.responsiveHazeSource
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.basic.FabPosition as MiuixFabPosition
+import top.yukonga.miuix.kmp.basic.Scaffold as MiuixScaffold
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun AppScaffold(
     modifier: Modifier = Modifier,
-    title: (@Composable () -> Unit)? = null,
-    subtitle: (@Composable () -> Unit)? = null,
-    scrollBehavior: TopAppBarScrollBehavior? = null,
-    navigationIcon: @Composable () -> Unit = {},
-    actions: @Composable RowScope.() -> Unit = {},
-    colors: TopAppBarColors = GlassTopAppBarDefaults.glassColors(),
-    topBar: @Composable () -> Unit = {},
+    topBar: @Composable (HazeState) -> Unit = {},
     bottomBar: @Composable () -> Unit = {},
     snackbarHost: @Composable () -> Unit = {},
     floatingActionButton: @Composable () -> Unit = {},
@@ -45,47 +42,73 @@ fun AppScaffold(
     val isDark = isSystemInDarkTheme()
     val hasImageBg = ThemeConfig.hasImageBg(isDark)
     val hazeState = remember { HazeState() }
+    val composeEngine = LegadoTheme.composeEngine
 
     val containerColor = if (hasImageBg) {
         Color.Transparent
     } else {
-        MaterialTheme.colorScheme.background
+        LegadoTheme.colorScheme.background
     }
 
-    val finalTopBar = @Composable {
-        Box(modifier = Modifier.responsiveHazeEffect(state = hazeState)) {
-            if (title != null) {
-                GlassMediumFlexibleTopAppBar(
-                    title = title,
-                    subtitle = subtitle,
-                    scrollBehavior = scrollBehavior,
-                    navigationIcon = navigationIcon,
-                    actions = actions,
-                    colors = colors
-                )
-            } else {
-                topBar()
-            }
-        }
+    val miuixContainerColor = if (hasImageBg) {
+        Color.Transparent
+    } else {
+        MiuixTheme.colorScheme.surface
     }
 
-    Scaffold(
-        modifier = modifier,
-        topBar = finalTopBar,
-        bottomBar = bottomBar,
-        snackbarHost = snackbarHost,
-        floatingActionButton = floatingActionButton,
-        floatingActionButtonPosition = floatingActionButtonPosition,
-        containerColor = containerColor,
-        contentColor = contentColor,
-        contentWindowInsets = contentWindowInsets
-    ) { paddingValues ->
-        Box(
-            modifier = Modifier
-                .fillMaxSize()
-                .responsiveHazeSource(hazeState)
-        ) {
-            content(paddingValues)
+    CompositionLocalProvider(LocalHazeState provides hazeState) {
+        when {
+            ThemeResolver.isMiuixEngine(composeEngine) -> {
+                val miuixFabPosition = when (floatingActionButtonPosition) {
+                    FabPosition.End -> MiuixFabPosition.End
+                    FabPosition.Center -> MiuixFabPosition.Center
+                    else -> MiuixFabPosition.End
+                }
+                MiuixScaffold(
+                    modifier = modifier,
+                    topBar = {
+                        topBar(hazeState)
+                    },
+                    bottomBar = bottomBar,
+                    snackbarHost = snackbarHost,
+                    floatingActionButton = floatingActionButton,
+                    floatingActionButtonPosition = miuixFabPosition,
+                    containerColor = miuixContainerColor,
+                    contentWindowInsets = contentWindowInsets
+                ) { paddingValues ->
+                    Box(
+                        modifier = Modifier
+                            .fillMaxSize()
+                            .responsiveHazeSource(hazeState)
+                    ) {
+                        content(paddingValues)
+                    }
+                }
+            }
+
+            else -> {
+                Scaffold(
+                    modifier = modifier,
+                    topBar = {
+                        topBar(hazeState)
+                    },
+                    bottomBar = bottomBar,
+                    snackbarHost = snackbarHost,
+                    floatingActionButton = floatingActionButton,
+                    floatingActionButtonPosition = floatingActionButtonPosition,
+                    containerColor = containerColor,
+                    contentColor = contentColor,
+                    contentWindowInsets = contentWindowInsets
+                ) { paddingValues ->
+                    Box(
+                        modifier = Modifier
+                            .fillMaxSize()
+                            .responsiveHazeSource(hazeState)
+                    ) {
+                        content(paddingValues)
+                    }
+                }
+            }
         }
     }
 }

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

@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.widthIn
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.material3.ContainedLoadingIndicator
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -24,6 +23,7 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import io.legado.app.ui.theme.LegadoTheme
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -70,7 +70,7 @@ fun EmptyMessageView(
 
         AnimatedTextLine(
             text = message,
-            style = MaterialTheme.typography.labelLarge,
+            style = LegadoTheme.typography.labelLarge,
             textAlign = TextAlign.Center,
             maxLines = 2,
             softWrap = true,

+ 0 - 113
app/src/main/java/io/legado/app/ui/widget/components/GlassMediumFlexibleTopAppBar.kt

@@ -1,113 +0,0 @@
-package io.legado.app.ui.widget.components
-
-import androidx.compose.foundation.layout.RowScope
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.MediumFlexibleTopAppBar
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarColors
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material3.TopAppBarScrollBehavior
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import io.legado.app.ui.config.themeConfig.ThemeConfig
-
-@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-fun GlassMediumFlexibleTopAppBar(
-    modifier: Modifier = Modifier,
-    title: @Composable () -> Unit,
-    subtitle: (@Composable () -> Unit)? = null,
-    scrollBehavior: TopAppBarScrollBehavior? = null,
-    navigationIcon: @Composable () -> Unit = {},
-    actions: @Composable RowScope.() -> Unit = {},
-    colors: TopAppBarColors = GlassTopAppBarDefaults.glassColors()
-) {
-    if (ThemeConfig.useFlexibleTopAppBar) {
-        MediumFlexibleTopAppBar(
-            modifier = modifier,
-            title = title,
-            subtitle = subtitle,
-            navigationIcon = navigationIcon,
-            actions = actions,
-            scrollBehavior = scrollBehavior,
-            colors = colors
-        )
-    } else {
-        TopAppBar(
-            modifier = modifier,
-            title = title,
-            navigationIcon = navigationIcon,
-            actions = actions,
-            scrollBehavior = scrollBehavior,
-            colors = colors
-        )
-    }
-}
-
-object GlassTopAppBarDefaults {
-
-    @OptIn(ExperimentalMaterial3Api::class)
-    @Composable
-    fun defaultScrollBehavior(): TopAppBarScrollBehavior {
-        return if (ThemeConfig.useFlexibleTopAppBar) {
-            TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
-        } else {
-            TopAppBarDefaults.pinnedScrollBehavior()
-        }
-    }
-
-    @Composable
-    fun glassColors(): TopAppBarColors {
-
-        val containerColor = GlassDefaults.glassColor(
-            noBlurColor = MaterialTheme.colorScheme.surface,
-            blurAlpha = GlassDefaults.TransparentAlpha
-        )
-
-        val scrolledContainerColor = if (ThemeConfig.enableBlur) {
-            MaterialTheme.colorScheme.surface.copy(alpha = GlassDefaults.TransparentAlpha)
-        } else {
-            MaterialTheme.colorScheme.surfaceContainer
-        }
-
-        return TopAppBarDefaults.topAppBarColors(
-            containerColor = applyTopBarOpacity(containerColor),
-            scrolledContainerColor = applyTopBarOpacity(scrolledContainerColor)
-        )
-    }
-
-    @Composable
-    fun containerColor(): Color {
-        val baseColor = GlassDefaults.glassColor(
-            noBlurColor = MaterialTheme.colorScheme.surface,
-            blurAlpha = GlassDefaults.TransparentAlpha
-        )
-        return applyTopBarOpacity(baseColor)
-    }
-
-    @Composable
-    fun scrolledContainerColor(): Color {
-        val baseColor = GlassDefaults.glassColor(
-            noBlurColor = MaterialTheme.colorScheme.surfaceContainer,
-            blurAlpha = GlassDefaults.TransparentAlpha
-        )
-        return applyTopBarOpacity(baseColor)
-    }
-
-    @Composable
-    fun controlContainerColor(): Color {
-        val baseColor = GlassDefaults.glassColor(
-            noBlurColor = MaterialTheme.colorScheme.surfaceContainerHighest,
-            blurAlpha = GlassDefaults.DefaultBlurAlpha
-        )
-        return applyTopBarOpacity(baseColor)
-    }
-
-    private fun applyTopBarOpacity(color: Color): Color {
-        val opacity = (ThemeConfig.topBarOpacity.coerceIn(0, 100)) / 100f
-        return color.copy(alpha = (color.alpha * opacity).coerceIn(0f, 1f))
-    }
-}

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

@@ -18,7 +18,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextField
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -31,9 +30,11 @@ 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.theme.LegadoTheme
 import io.legado.app.ui.widget.components.button.SmallTextButton
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
 import io.legado.app.ui.widget.components.settingItem.SettingItem
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -52,10 +53,10 @@ fun GroupManageBottomSheet(
                 .padding(bottom = 16.dp),
             horizontalAlignment = Alignment.CenterHorizontally,
         ) {
-            Text(
+            AppText(
                 modifier = Modifier.padding(bottom = 16.dp),
                 text = stringResource(R.string.group_manage),
-                style = MaterialTheme.typography.titleMedium
+                style = LegadoTheme.typography.titleMedium
             )
             LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                 items(groups, key = { it }) { group ->
@@ -115,7 +116,7 @@ private fun GroupItem(
                 modifier = Modifier
                     .fillMaxWidth()
                     .heightIn(min = 48.dp),
-                label = { Text(stringResource(R.string.edit)) },
+                label = { AppText(stringResource(R.string.edit)) },
                 contentPadding = PaddingValues(
                     top = 4.dp,
                     bottom = 4.dp,

+ 34 - 0
app/src/main/java/io/legado/app/ui/widget/components/IconSwitch.kt

@@ -10,6 +10,40 @@ import androidx.compose.material3.SwitchDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.basic.Switch as MiuixSwitch
+
+@Composable
+fun AdaptiveSwitch(
+    checked: Boolean,
+    onCheckedChange: (Boolean) -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    checkedIcon: ImageVector = Icons.Filled.Check,
+    uncheckedIcon: ImageVector? = null,
+    showIcon: Boolean = true
+) {
+    val composeEngine = LegadoTheme.composeEngine
+
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        MiuixSwitch(
+            checked = checked,
+            onCheckedChange = onCheckedChange,
+            modifier = modifier,
+            enabled = enabled
+        )
+    } else {
+        IconSwitch(
+            checked = checked,
+            onCheckedChange = onCheckedChange,
+            enabled = enabled,
+            checkedIcon = checkedIcon,
+            uncheckedIcon = uncheckedIcon,
+            showIcon = showIcon
+        )
+    }
+}
 
 @Composable
 fun IconSwitch(

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

@@ -26,7 +26,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextField
 import androidx.compose.material3.TextFieldDefaults
 import androidx.compose.runtime.Composable
@@ -43,6 +42,7 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
 import io.legado.app.ui.widget.components.button.SmallIconButton
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 
@@ -104,7 +104,7 @@ fun SearchBarSection(
                 .fillMaxWidth()
                 .heightIn(min = 48.dp)
                 .padding(horizontal = 4.dp),
-            placeholder = { Text(placeholder) },
+            placeholder = { AppText(placeholder) },
             leadingIcon = leadingIcon,
             trailingIcon = {
                 Row(

+ 3 - 3
app/src/main/java/io/legado/app/ui/widget/components/SelectionBottomBar.kt

@@ -15,7 +15,6 @@ import androidx.compose.material3.HorizontalFloatingToolbar
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.PlainTooltip
-import androidx.compose.material3.Text
 import androidx.compose.material3.TooltipAnchorPosition
 import androidx.compose.material3.TooltipBox
 import androidx.compose.material3.TooltipDefaults
@@ -27,6 +26,7 @@ import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.widget.components.text.AppText
 
 data class SelectionActions(
     val primaryAction: ActionItem,
@@ -84,7 +84,7 @@ fun SelectionBottomBar(
                     ) {
                         secondaryActions.forEach { action ->
                             DropdownMenuItem(
-                                text = { Text(action.text) },
+                                text = { AppText(action.text) },
                                 leadingIcon = action.icon,
                                 onClick = {
                                     action.onClick()
@@ -101,7 +101,7 @@ fun SelectionBottomBar(
                 positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
                     TooltipAnchorPosition.Above
                 ),
-                tooltip = { PlainTooltip { Text(primaryAction.text) } },
+                tooltip = { PlainTooltip { AppText(primaryAction.text) } },
                 state = rememberTooltipState(),
             ) {
                 FilledIconButton(

+ 25 - 16
app/src/main/java/io/legado/app/ui/widget/components/SplicedColumnGroup.kt

@@ -7,14 +7,14 @@ import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.Card
-import androidx.compose.material3.CardDefaults
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.draw.clip
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.title.AdaptiveTitle
+import top.yukonga.miuix.kmp.basic.Card as MiuixCard
 
 /**
  * Settings Group Container by https://github.com/wxxsfxyzm/InstallerX-Revived
@@ -29,24 +29,33 @@ fun SplicedColumnGroup(
     title: String = "",
     content: @Composable ColumnScope.() -> Unit,
 ) {
-    Column(modifier = modifier.padding(top = 8.dp, bottom = 16.dp)) {
+    val composeEngine = LegadoTheme.composeEngine
+    Column(modifier = modifier.padding(top = 8.dp, bottom = 8.dp)) {
         if (title.isNotEmpty()) {
-            Text(
+            AdaptiveTitle(
                 text = title,
-                style = MaterialTheme.typography.labelLarge,
-                color = MaterialTheme.colorScheme.primary,
                 modifier = Modifier.padding(start = 16.dp, bottom = 8.dp)
             )
         }
 
-        Card(
-            shape = RoundedCornerShape(16.dp),
-            colors = CardDefaults.cardColors(containerColor = Color.Transparent),
-            modifier = Modifier
-                .fillMaxWidth()
-                .animateContentSize()
-        ) {
+        if (ThemeResolver.isMiuixEngine(composeEngine)) {
+            MiuixCard {
+                Column(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .animateContentSize()
+                        .clip(RoundedCornerShape(16.dp))
+                ) {
+                    content()
+                }
+            }
+
+        } else {
             Column(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .animateContentSize()
+                    .clip(RoundedCornerShape(16.dp)),
                 verticalArrangement = Arrangement.spacedBy(2.dp)
             ) {
                 content()

+ 12 - 11
app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt

@@ -15,7 +15,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -26,7 +25,9 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import io.legado.app.data.entities.Bookmark
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -50,16 +51,16 @@ fun BookmarkEditSheet(
                 .padding(16.dp)
                 .navigationBarsPadding()
         ) {
-            Text(
+            AppText(
                 text = bookmark.chapterName,
-                style = MaterialTheme.typography.titleMedium,
+                style = LegadoTheme.typography.titleMedium,
                 modifier = Modifier.padding(bottom = 16.dp)
             )
 
             OutlinedTextField(
                 value = bookText,
                 onValueChange = { bookText = it },
-                label = { Text("原文") },
+                label = { AppText("原文") },
                 modifier = Modifier.fillMaxWidth(),
                 maxLines = 10
             )
@@ -69,7 +70,7 @@ fun BookmarkEditSheet(
             OutlinedTextField(
                 value = content,
                 onValueChange = { content = it },
-                label = { Text("摘要/笔记") },
+                label = { AppText("摘要/笔记") },
                 modifier = Modifier.fillMaxWidth(),
                 maxLines = 5
             )
@@ -86,7 +87,7 @@ fun BookmarkEditSheet(
                     colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.error),
                     modifier = Modifier.weight(1f)
                 ) {
-                    Text("删除")
+                    AppText("删除")
                 }
 
                 Button(
@@ -99,7 +100,7 @@ fun BookmarkEditSheet(
                     },
                     modifier = Modifier.weight(1f)
                 ) {
-                    Text("保存")
+                    AppText("保存")
                 }
             }
             Spacer(modifier = Modifier.height(16.dp))
@@ -109,8 +110,8 @@ fun BookmarkEditSheet(
     if (showDeleteConfirmDialog) {
         AlertDialog(
             onDismissRequest = { showDeleteConfirmDialog = false },
-            title = { Text("确认删除") },
-            text = { Text("你确定要删除这条书签吗?") },
+            title = { AppText("确认删除") },
+            text = { AppText("你确定要删除这条书签吗?") },
             confirmButton = {
                 TextButton(
                     onClick = {
@@ -119,14 +120,14 @@ fun BookmarkEditSheet(
                     },
                     colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error)
                 ) {
-                    Text("删除")
+                    AppText("删除")
                 }
             },
             dismissButton = {
                 TextButton(
                     onClick = { showDeleteConfirmDialog = false }
                 ) {
-                    Text("取消")
+                    AppText("取消")
                 }
             }
         )

+ 8 - 7
app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt

@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
@@ -19,6 +18,8 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import io.legado.app.data.entities.Bookmark
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -49,17 +50,17 @@ fun BookmarkItem(
                 .fillMaxWidth()
                 .padding(horizontal = 16.dp, vertical = 12.dp)
         ) {
-            Text(
+            AppText(
                 text = bookmark.chapterName,
-                style = MaterialTheme.typography.titleSmallEmphasized,
+                style = LegadoTheme.typography.titleSmallEmphasized,
                 color = if (isDur) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary
             )
 
             if (bookmark.bookText.isNotEmpty()) {
                 Spacer(modifier = Modifier.height(4.dp))
-                Text(
+                AppText(
                     text = bookmark.bookText,
-                    style = MaterialTheme.typography.bodyMedium,
+                    style = LegadoTheme.typography.bodyMedium,
                     maxLines = 2,
                     overflow = TextOverflow.Ellipsis,
                     color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -68,9 +69,9 @@ fun BookmarkItem(
 
             if (bookmark.content.isNotEmpty()) {
                 Spacer(modifier = Modifier.height(2.dp))
-                Text(
+                AppText(
                     text = bookmark.content,
-                    style = MaterialTheme.typography.bodyMedium,
+                    style = LegadoTheme.typography.bodyMedium,
                     color = MaterialTheme.colorScheme.primary
                 )
             }

+ 2 - 2
app/src/main/java/io/legado/app/ui/widget/components/button/AlertButton.kt

@@ -3,10 +3,10 @@ package io.legado.app.ui.widget.components.button
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
+import io.legado.app.ui.widget.components.text.AppText
 
 @Composable
 fun AlertButton(
@@ -24,6 +24,6 @@ fun AlertButton(
             containerColor = Color.Transparent,
         )
     ) {
-        Text(text = text)
+        AppText(text = text)
     }
 }

+ 4 - 4
app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedActionButton.kt

@@ -8,8 +8,6 @@ import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.ToggleButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -21,6 +19,8 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.delay
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@@ -73,9 +73,9 @@ fun AnimatedActionButton(
             AnimatedVisibility(
                 visible = showText
             ) {
-                Text(
+                AppText(
                     text = if (lastCheckedState) activeText else inactiveText,
-                    style = MaterialTheme.typography.labelMedium,
+                    style = LegadoTheme.typography.labelMedium,
                     modifier = Modifier.padding(start = 8.dp),
                     maxLines = 1,
                     softWrap = false

+ 2 - 2
app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedTextButton.kt

@@ -8,11 +8,11 @@ import androidx.compose.animation.fadeOut
 import androidx.compose.animation.togetherWith
 import androidx.compose.material3.ContainedLoadingIndicator
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -38,7 +38,7 @@ fun AnimatedTextButton(
             if (loading) {
                 ContainedLoadingIndicator()
             } else {
-                Text(text)
+                AppText(text)
             }
         }
     }

+ 57 - 0
app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt

@@ -0,0 +1,57 @@
+package io.legado.app.ui.widget.components.button
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
+import io.legado.app.R
+import top.yukonga.miuix.kmp.basic.Icon
+import top.yukonga.miuix.kmp.basic.IconButton
+import top.yukonga.miuix.kmp.icon.MiuixIcons
+import top.yukonga.miuix.kmp.icon.extended.Back
+import top.yukonga.miuix.kmp.theme.LocalContentColor
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+
+@Composable
+fun MiuixButton(
+    modifier: Modifier = Modifier,
+    imageVector: ImageVector = MiuixIcons.Regular.Back,
+    tint: Color = LocalContentColor.current,
+    contentDescription: String? = stringResource(id = R.string.back),
+    onClick: () -> Unit,
+) {
+    IconButton(
+        onClick = onClick,
+        modifier = modifier
+    ) {
+        Icon(
+            imageVector = imageVector,
+            contentDescription = contentDescription,
+            tint = tint
+        )
+    }
+}
+
+@Composable
+fun MiuixToggleButton(
+    modifier: Modifier = Modifier,
+    checked: Boolean,
+    onCheckedChange: (Boolean) -> Unit,
+    iconChecked: ImageVector,
+    iconUnchecked: ImageVector = iconChecked,
+    checkedTint: Color = MiuixTheme.colorScheme.primary,
+    uncheckedTint: Color = LocalContentColor.current,
+    contentDescription: String? = null,
+) {
+    IconButton(
+        onClick = { onCheckedChange(!checked) },
+        modifier = modifier
+    ) {
+        Icon(
+            imageVector = if (checked) iconChecked else iconUnchecked,
+            contentDescription = contentDescription,
+            tint = if (checked) checkedTint else uncheckedTint
+        )
+    }
+}

+ 31 - 16
app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt

@@ -15,11 +15,9 @@ import androidx.compose.material3.IconButton
 import androidx.compose.material3.IconButtonDefaults
 import androidx.compose.material3.IconToggleButtonShapes
 import androidx.compose.material3.LocalMinimumInteractiveComponentSize
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedIconButton
 import androidx.compose.material3.OutlinedIconToggleButton
 import androidx.compose.material3.OutlinedToggleButton
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
@@ -31,7 +29,13 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.delay
+import top.yukonga.miuix.kmp.basic.Icon as MiuixIcon
+import top.yukonga.miuix.kmp.basic.IconButton as MiuixIconButton
 
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@@ -41,22 +45,33 @@ fun SmallIconButton(
     icon: ImageVector,
     contentDescription: String? = null
 ) {
-    CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
-        IconButton(
-            onClick = onClick,
-            modifier = Modifier.size(
-                IconButtonDefaults.extraSmallContainerSize(
-                    IconButtonDefaults.IconButtonWidthOption.Uniform
-                )
-            ),
-            shape = IconButtonDefaults.extraSmallRoundShape,
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        MiuixIconButton(
+            onClick = onClick
         ) {
-            Icon(
+            MiuixIcon(
                 imageVector = icon,
-                contentDescription = contentDescription,
-                modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize),
+                contentDescription = contentDescription
             )
         }
+    } else {
+        CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
+            IconButton(
+                onClick = onClick,
+                modifier = Modifier.size(
+                    IconButtonDefaults.extraSmallContainerSize(
+                        IconButtonDefaults.IconButtonWidthOption.Uniform
+                    )
+                ),
+                shape = IconButtonDefaults.extraSmallRoundShape,
+            ) {
+                Icon(
+                    imageVector = icon,
+                    contentDescription = contentDescription,
+                    modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize),
+                )
+            }
+        }
     }
 }
 
@@ -204,9 +219,9 @@ fun SmallAnimatedActionButton(
                 AnimatedVisibility(
                     visible = showText
                 ) {
-                    Text(
+                    AppText(
                         text = if (lastCheckedState) activeText else inactiveText,
-                        style = MaterialTheme.typography.labelSmall,
+                        style = LegadoTheme.typography.labelSmall,
                         modifier = Modifier.padding(start = 6.dp),
                         maxLines = 1,
                         softWrap = false

+ 4 - 3
app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt

@@ -6,12 +6,13 @@ import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.text.AppText
 
 @Composable
 fun SmallTextButton(
@@ -32,9 +33,9 @@ fun SmallTextButton(
             modifier = Modifier.size(16.dp)
         )
         Spacer(Modifier.width(4.dp))
-        Text(
+        AppText(
             text = text,
-            style = MaterialTheme.typography.labelMedium
+            style = LegadoTheme.typography.labelMedium
         )
     }
 }

+ 78 - 51
app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt

@@ -22,7 +22,6 @@ import androidx.compose.material3.IconButton
 import androidx.compose.material3.IconButtonDefaults
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedIconButton
-import androidx.compose.material3.Text
 import androidx.compose.material3.ToggleButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -35,7 +34,10 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
 import io.legado.app.ui.config.themeConfig.ThemeConfig
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import kotlinx.coroutines.delay
 
 enum class TopBarButtonVariant {
@@ -109,13 +111,22 @@ fun TopbarNavigationButton(
     contentDescription: String? = "返回",
     style: TopBarButtonVariant = TopBarButtonVariant.Filled
 ) {
-    TopBarButton(
-        onClick = onClick,
-        imageVector = imageVector,
-        contentDescription = contentDescription,
-        modifier = modifier.padding(horizontal = 12.dp),
-        style = style
-    )
+    if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
+        MiuixButton(
+            onClick = onClick,
+            imageVector = imageVector,
+            contentDescription = contentDescription,
+            modifier = modifier.padding(horizontal = 16.dp)
+        )
+    } else {
+        TopBarButton(
+            onClick = onClick,
+            imageVector = imageVector,
+            contentDescription = contentDescription,
+            modifier = modifier.padding(horizontal = 12.dp),
+            style = style
+        )
+    }
 }
 
 @Composable
@@ -126,21 +137,29 @@ fun TopBarActionButton(
     modifier: Modifier = Modifier
 ) {
     val enableProgressive = ThemeConfig.enableProgressiveBlur
-
-    if (enableProgressive) {
-        TopBarButton(
+    if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
+        MiuixButton(
             onClick = onClick,
             imageVector = imageVector,
             contentDescription = contentDescription,
-            modifier = modifier.padding(end = 12.dp),
-            style = TopBarButtonVariant.Filled
+            modifier = modifier.padding(end = 8.dp),
         )
     } else {
-        IconButton(onClick = onClick) {
-            Icon(
+        if (enableProgressive) {
+            TopBarButton(
+                onClick = onClick,
                 imageVector = imageVector,
-                contentDescription = contentDescription
+                contentDescription = contentDescription,
+                modifier = modifier.padding(end = 12.dp),
+                style = TopBarButtonVariant.Filled
             )
+        } else {
+            IconButton(onClick = onClick) {
+                Icon(
+                    imageVector = imageVector,
+                    contentDescription = contentDescription
+                )
+            }
         }
     }
 }
@@ -165,43 +184,51 @@ fun TopBarAnimatedActionButton(
             showText = false
         }
     }
-
-    ToggleButton(
-        modifier = modifier.height(36.dp),
-        contentPadding = PaddingValues(horizontal = 8.dp),
-        checked = checked,
-        onCheckedChange = {
-            lastCheckedState = it
-            onCheckedChange(it)
-            showText = true
-        }
-    ) {
-        Row(
-            verticalAlignment = Alignment.CenterVertically,
-            horizontalArrangement = Arrangement.Center
+    if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
+        MiuixToggleButton(
+            checked = checked,
+            onCheckedChange = onCheckedChange,
+            iconChecked = iconChecked,
+            iconUnchecked = iconUnchecked
+        )
+    } else {
+        ToggleButton(
+            modifier = modifier.height(36.dp),
+            contentPadding = PaddingValues(horizontal = 8.dp),
+            checked = checked,
+            onCheckedChange = {
+                lastCheckedState = it
+                onCheckedChange(it)
+                showText = true
+            }
         ) {
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                horizontalArrangement = Arrangement.Center
+            ) {
 
-            AnimatedContent(
-                targetState = checked,
-                label = "IconAnimation"
-            ) { targetChecked ->
-                AnimatedIcon(
-                    modifier = Modifier.size(20.dp),
-                    imageVector = if (targetChecked) iconChecked else iconUnchecked,
-                    contentDescription = null
-                )
-            }
+                AnimatedContent(
+                    targetState = checked,
+                    label = "IconAnimation"
+                ) { targetChecked ->
+                    AnimatedIcon(
+                        modifier = Modifier.size(20.dp),
+                        imageVector = if (targetChecked) iconChecked else iconUnchecked,
+                        contentDescription = null
+                    )
+                }
 
-            AnimatedVisibility(
-                visible = showText
-            ) {
-                Text(
-                    text = if (lastCheckedState) activeText else inactiveText,
-                    style = MaterialTheme.typography.labelMedium,
-                    modifier = Modifier.padding(start = 8.dp),
-                    maxLines = 1,
-                    softWrap = false
-                )
+                AnimatedVisibility(
+                    visible = showText
+                ) {
+                    AppText(
+                        text = if (lastCheckedState) activeText else inactiveText,
+                        style = LegadoTheme.typography.labelMedium,
+                        modifier = Modifier.padding(start = 8.dp),
+                        maxLines = 1,
+                        softWrap = false
+                    )
+                }
             }
         }
     }

+ 104 - 32
app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt

@@ -4,58 +4,130 @@ import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.material.ExperimentalMaterialApi
 import androidx.compose.material3.Card
-import androidx.compose.material3.CardColors
 import androidx.compose.material3.CardDefaults
 import androidx.compose.material3.CardElevation
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.Dp
 import io.legado.app.ui.config.themeConfig.ThemeConfig
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.basic.Card as MiuixCard
+import top.yukonga.miuix.kmp.basic.CardDefaults as MiuixCardDefaults
 
 @OptIn(ExperimentalMaterialApi::class)
 @Composable
-fun GlassCard(
+private fun BaseCard(
     modifier: Modifier = Modifier,
     onClick: (() -> Unit)? = null,
     shape: Shape = CardDefaults.shape,
-    colors: CardColors? = null,
+    cornerRadius: Dp = MiuixCardDefaults.CornerRadius,
+    containerColor: Color? = null,
+    contentColor: Color? = null,
     elevation: CardElevation = CardDefaults.cardElevation(),
     border: BorderStroke? = null,
+    alpha: Float = 1f,
     content: @Composable ColumnScope.() -> Unit
 ) {
-    val containerAlpha = ThemeConfig.containerOpacity / 100f
-
-    val baseColors = colors ?: CardDefaults.cardColors(
-        containerColor = MaterialTheme.colorScheme.secondaryContainer,
-        contentColor = MaterialTheme.colorScheme.onSecondaryContainer
-    )
-
-    val finalColors = CardDefaults.cardColors(
-        containerColor = baseColors.containerColor.copy(alpha = containerAlpha),
-        contentColor = baseColors.contentColor,
-        disabledContainerColor = baseColors.disabledContainerColor.copy(alpha = containerAlpha),
-        disabledContentColor = baseColors.disabledContentColor
-    )
-
-    if (onClick != null) {
-        Card(
-            onClick = onClick,
+    if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
+        val colors = MiuixCardDefaults.defaultColors(
+            color = (containerColor
+                ?: MiuixTheme.colorScheme.secondaryContainer).copy(alpha = alpha),
+            contentColor = contentColor ?: MiuixTheme.colorScheme.onSurface
+        )
+        MiuixCard(
             modifier = modifier,
-            shape = shape,
-            colors = finalColors,
-            elevation = elevation,
-            border = border,
-            content = content
+            cornerRadius = cornerRadius,
+            onClick = onClick,
+            content = content,
+            colors = colors
         )
     } else {
-        Card(
-            modifier = modifier,
-            shape = shape,
-            colors = finalColors,
-            elevation = elevation,
-            border = border,
-            content = content
+        val colors = CardDefaults.cardColors(
+            containerColor = (containerColor ?: MaterialTheme.colorScheme.secondaryContainer).copy(
+                alpha = alpha
+            ),
+            contentColor = contentColor ?: MaterialTheme.colorScheme.onSecondaryContainer,
+            disabledContainerColor = MaterialTheme.colorScheme.onSecondaryContainer.copy(alpha = alpha * 0.38f),
+            disabledContentColor = MaterialTheme.colorScheme.onSecondaryContainer.copy(alpha = alpha * 0.38f)
         )
+        if (onClick != null) {
+            Card(
+                modifier = modifier,
+                shape = shape,
+                colors = colors,
+                elevation = elevation,
+                border = border,
+                onClick = onClick,
+                content = content
+            )
+        } else {
+            Card(
+                modifier = modifier,
+                shape = shape,
+                colors = colors,
+                elevation = elevation,
+                border = border,
+                content = content
+            )
+        }
     }
 }
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun GlassCard(
+    modifier: Modifier = Modifier,
+    onClick: (() -> Unit)? = null,
+    shape: Shape = CardDefaults.shape,
+    cornerRadius: Dp = MiuixCardDefaults.CornerRadius,
+    containerColor: Color? = null,
+    contentColor: Color? = null,
+    elevation: CardElevation = CardDefaults.cardElevation(),
+    border: BorderStroke? = null,
+    content: @Composable ColumnScope.() -> Unit
+) {
+    BaseCard(
+        modifier = modifier,
+        onClick = onClick,
+        shape = shape,
+        cornerRadius = cornerRadius,
+        containerColor = containerColor,
+        contentColor = contentColor,
+        elevation = elevation,
+        border = border,
+        alpha = ThemeConfig.containerOpacity / 100f,
+        content = content
+    )
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun NormalCard(
+    modifier: Modifier = Modifier,
+    onClick: (() -> Unit)? = null,
+    shape: Shape = CardDefaults.shape,
+    cornerRadius: Dp = MiuixCardDefaults.CornerRadius,
+    containerColor: Color? = null,
+    contentColor: Color? = null,
+    elevation: CardElevation = CardDefaults.cardElevation(),
+    border: BorderStroke? = null,
+    content: @Composable ColumnScope.() -> Unit
+) {
+    BaseCard(
+        modifier = modifier,
+        onClick = onClick,
+        shape = shape,
+        cornerRadius = cornerRadius,
+        containerColor = containerColor,
+        contentColor = contentColor,
+        elevation = elevation,
+        border = border,
+        alpha = 1f,
+        content = content
+    )
+}

+ 48 - 19
app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt

@@ -24,8 +24,6 @@ import androidx.compose.material3.Checkbox
 import androidx.compose.material3.ListItem
 import androidx.compose.material3.ListItemDefaults
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Switch
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -41,10 +39,17 @@ import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.AdaptiveSwitch
 import io.legado.app.ui.widget.components.button.SmallIconButton
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
+import io.legado.app.ui.widget.components.text.AppText
 import sh.calvin.reorderable.ReorderableItem
 import sh.calvin.reorderable.ReorderableLazyListState
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.theme.MiuixTheme
 
 @Composable
 fun SelectionItemCard(
@@ -66,11 +71,14 @@ fun SelectionItemCard(
 ) {
     var showMenu by remember { mutableStateOf(false) }
 
+    val composeEngine = ThemeResolver.isMiuixEngine(composeEngine)
     val animatedContainerColor by animateColorAsState(
         targetValue = if (isSelected)
-            selectedContainerColor ?: MaterialTheme.colorScheme.secondaryContainer
+            selectedContainerColor
+                ?: if (composeEngine) MiuixTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.secondaryContainer
         else
-            containerColor ?: MaterialTheme.colorScheme.surfaceContainerLow,
+            containerColor
+                ?: if (composeEngine) MiuixTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.surfaceContainerLow,
         animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing),
         label = "CardColor"
     )
@@ -81,7 +89,7 @@ fun SelectionItemCard(
             .padding(horizontal = 16.dp)
             .fillMaxWidth(),
         shape = MaterialTheme.shapes.medium,
-        colors = CardDefaults.cardColors(containerColor = animatedContainerColor),
+        containerColor = animatedContainerColor,
         elevation = CardDefaults.cardElevation(defaultElevation = elevation)
     ) {
         Row(
@@ -113,28 +121,49 @@ fun SelectionItemCard(
                 }
             }
 
-            ListItem(
-                modifier = Modifier.weight(1f),
-                headlineContent = {
-                    Text(
+            if (composeEngine) {
+                BasicComponent(
+                    modifier = Modifier.weight(1f)
+                ) {
+                    AppText(
                         text = title,
-                        style = MaterialTheme.typography.titleSmall,
+                        style = LegadoTheme.typography.titleSmall,
                         maxLines = 1,
                         overflow = TextOverflow.Ellipsis
                     )
-                },
-                supportingContent = if (!subtitle.isNullOrBlank()) {
-                    {
-                        Text(
+                    if (!subtitle.isNullOrBlank()) {
+                        AppText(
                             text = subtitle,
-                            style = MaterialTheme.typography.bodySmall,
+                            style = LegadoTheme.typography.bodySmall,
                             maxLines = 1,
                             overflow = TextOverflow.Ellipsis
                         )
                     }
-                } else null,
-                colors = ListItemDefaults.colors(containerColor = Color.Transparent)
-            )
+                }
+            } else {
+                ListItem(
+                    modifier = Modifier.weight(1f),
+                    headlineContent = {
+                        AppText(
+                            text = title,
+                            style = LegadoTheme.typography.titleSmall,
+                            maxLines = 1,
+                            overflow = TextOverflow.Ellipsis
+                        )
+                    },
+                    supportingContent = if (!subtitle.isNullOrBlank()) {
+                        {
+                            AppText(
+                                text = subtitle,
+                                style = LegadoTheme.typography.bodySmall,
+                                maxLines = 1,
+                                overflow = TextOverflow.Ellipsis
+                            )
+                        }
+                    } else null,
+                    colors = ListItemDefaults.colors(containerColor = Color.Transparent)
+                )
+            }
 
             Row(
                 verticalAlignment = Alignment.CenterVertically,
@@ -143,7 +172,7 @@ fun SelectionItemCard(
                     .padding(end = 8.dp)
             ) {
                 onEnabledChange?.let {
-                    Switch(
+                    AdaptiveSwitch(
                         modifier = Modifier.scale(0.8f),
                         checked = isEnabled,
                         onCheckedChange = it

+ 75 - 0
app/src/main/java/io/legado/app/ui/widget/components/card/SettingCard.kt

@@ -0,0 +1,75 @@
+package io.legado.app.ui.widget.components.card
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardColors
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.CardElevation
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Shape
+import io.legado.app.ui.config.themeConfig.ThemeConfig
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.basic.BasicComponent
+
+// import top.yukonga.miuix.kmp.basic.theme.LocalColors as MiuixLocalColors
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun SettingCard(
+    modifier: Modifier = Modifier,
+    onClick: (() -> Unit)? = null,
+    shape: Shape = CardDefaults.shape,
+    colors: CardColors? = null,
+    elevation: CardElevation = CardDefaults.cardElevation(),
+    border: BorderStroke? = null,
+    content: @Composable ColumnScope.() -> Unit
+) {
+    val composeEngine = LegadoTheme.composeEngine
+    val containerAlpha = ThemeConfig.containerOpacity / 100f
+
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        BasicComponent(
+            modifier = modifier,
+            onClick = onClick,
+            content = content
+        )
+    } else {
+        val baseColors = colors ?: CardDefaults.cardColors(
+            containerColor = MaterialTheme.colorScheme.secondaryContainer,
+            contentColor = MaterialTheme.colorScheme.onSecondaryContainer
+        )
+
+        val finalColors = CardDefaults.cardColors(
+            containerColor = baseColors.containerColor.copy(alpha = containerAlpha),
+            contentColor = baseColors.contentColor,
+            disabledContainerColor = baseColors.disabledContainerColor.copy(alpha = containerAlpha),
+            disabledContentColor = baseColors.disabledContentColor
+        )
+
+        if (onClick != null) {
+            Card(
+                onClick = onClick,
+                modifier = modifier,
+                shape = shape,
+                colors = finalColors,
+                elevation = elevation,
+                border = border,
+                content = content
+            )
+        } else {
+            Card(
+                modifier = modifier,
+                shape = shape,
+                colors = finalColors,
+                elevation = elevation,
+                border = border,
+                content = content
+            )
+        }
+    }
+}

+ 9 - 17
app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt

@@ -6,50 +6,42 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.MaterialTheme.colorScheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.AnimatedTextLine
 
-@Preview(showBackground = true)
-@Composable
-fun PreviewTextCard() {
-    MaterialTheme {
-        TextCard(
-            text = "v1.0.0"
-        )
-    }
-}
 
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
 fun TextCard(
     modifier: Modifier = Modifier,
     text: String,
     icon: ImageVector? = null,
     onClick: (() -> Unit)? = null,
-    backgroundColor: Color = colorScheme.primaryContainer,
-    contentColor: Color = colorScheme.onPrimaryContainer,
+    backgroundColor: Color = MaterialTheme.colorScheme.primaryContainer,
+    contentColor: Color = MaterialTheme.colorScheme.onPrimaryContainer,
     cornerRadius: Dp = 8.dp,
     horizontalPadding: Dp = 8.dp,
     verticalPadding: Dp = 2.dp,
     iconSize: Dp = 14.dp,
     spacing: Dp = 4.dp,
-    textStyle: TextStyle = MaterialTheme.typography.labelSmall
+    textStyle: TextStyle = LegadoTheme.typography.labelSmallEmphasized
 ) {
-    GlassCard(
+    NormalCard(
         modifier = modifier,
         shape = RoundedCornerShape(cornerRadius),
-        colors = CardDefaults.cardColors(containerColor = backgroundColor),
+        containerColor = backgroundColor,
+        contentColor = contentColor,
         onClick = onClick
     ) {
         Row(

+ 4 - 3
app/src/main/java/io/legado/app/ui/widget/components/checkBox/CheckboxItem.kt

@@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material3.Checkbox
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
+import io.legado.app.ui.widget.components.text.AppText
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -15,6 +15,7 @@ import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
 
 @Composable
 fun CheckboxItem(
@@ -45,9 +46,9 @@ fun CheckboxItem(
             enabled = enabled,
             modifier = Modifier.alpha(alpha)
         )
-        Text(
+        AppText(
             text = title,
-            style = MaterialTheme.typography.bodyMedium,
+            style = LegadoTheme.typography.bodyMedium,
             maxLines = 1,
             modifier = Modifier
                 .padding(start = 12.dp)

+ 18 - 4
app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt

@@ -13,7 +13,11 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.StrokeCap
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.card.TextCard
+import top.yukonga.miuix.kmp.theme.MiuixTheme
 
 @Composable
 fun BookshelfCover(
@@ -27,6 +31,16 @@ fun BookshelfCover(
     sourceOrigin: String? = null,
     onLoadFinish: (() -> Unit)? = null
 ) {
+    val backgroundColor = if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        MiuixTheme.colorScheme.primaryContainer.copy(alpha = 0.2f)
+    } else {
+        MaterialTheme.colorScheme.secondaryContainer
+    }
+    val contentColor = if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        MiuixTheme.colorScheme.primary
+    } else {
+        MaterialTheme.colorScheme.onSecondaryContainer
+    }
     Box(modifier = modifier) {
         BookCover(
             name = name,
@@ -44,8 +58,8 @@ fun BookshelfCover(
                 modifier = Modifier
                     .align(Alignment.TopEnd)
                     .padding(2.dp),
-                backgroundColor = MaterialTheme.colorScheme.secondaryContainer,
-                contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
+                backgroundColor = backgroundColor,
+                contentColor = contentColor,
                 cornerRadius = 4.dp,
                 horizontalPadding = 4.dp,
                 verticalPadding = 0.dp
@@ -59,8 +73,8 @@ fun BookshelfCover(
                     .fillMaxWidth()
                     .padding(horizontal = 4.dp, vertical = 6.dp)
                     .height(3.dp),
-                color = MaterialTheme.colorScheme.primary,
-                trackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f),
+                color = LegadoTheme.colorScheme.primary,
+                trackColor = LegadoTheme.colorScheme.primary.copy(alpha = 0.2f),
                 strokeCap = StrokeCap.Round
             )
         }

+ 8 - 7
app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt

@@ -22,7 +22,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.Button
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -41,7 +40,9 @@ import com.github.skydoves.colorpicker.compose.BrightnessSlider
 import com.github.skydoves.colorpicker.compose.HsvColorPicker
 import com.github.skydoves.colorpicker.compose.rememberColorPickerController
 import io.legado.app.R
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -86,9 +87,9 @@ fun ColorPickerSheet(
                 .padding(16.dp),
             horizontalAlignment = Alignment.CenterHorizontally
         ) {
-            Text(
+            AppText(
                 text = "颜色选择",
-                style = MaterialTheme.typography.titleLarge,
+                style = LegadoTheme.typography.titleLarge,
                 modifier = Modifier.padding(bottom = 16.dp)
             )
 
@@ -168,9 +169,9 @@ fun ColorPickerSheet(
                         )
                 )
                 Spacer(modifier = Modifier.width(12.dp))
-                Text(
+                AppText(
                     text = "#${Integer.toHexString(currentColor.toArgb()).uppercase()}",
-                    style = MaterialTheme.typography.bodyLarge
+                    style = LegadoTheme.typography.bodyLarge
                 )
 
                 Row(
@@ -178,14 +179,14 @@ fun ColorPickerSheet(
                     horizontalArrangement = Arrangement.End
                 ) {
                     TextButton(onClick = onDismissRequest) {
-                        Text(stringResource(R.string.cancel))
+                        AppText(stringResource(R.string.cancel))
                     }
                     Spacer(modifier = Modifier.width(8.dp))
                     Button(onClick = {
                         onColorSelected(currentColor.toArgb())
                         onDismissRequest()
                     }) {
-                        Text(stringResource(R.string.ok))
+                        AppText(stringResource(R.string.ok))
                     }
                 }
             }

+ 9 - 9
app/src/main/java/io/legado/app/ui/widget/components/dialog/TextListInputDialog.kt

@@ -10,9 +10,7 @@ import androidx.compose.foundation.lazy.LazyRow
 import androidx.compose.foundation.lazy.items
 import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.AssistChip
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -22,6 +20,8 @@ import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.text.AppText
 
 @Composable
 fun TextListInputDialog(
@@ -36,22 +36,22 @@ fun TextListInputDialog(
 
     AlertDialog(
         onDismissRequest = onDismissRequest,
-        title = { Text(title) },
+        title = { AppText(title) },
         text = {
             Column {
                 OutlinedTextField(
                     value = text,
                     onValueChange = { text = it },
-                    label = { Text(hint) },
+                    label = { AppText(hint) },
                     modifier = Modifier.fillMaxWidth(),
                     singleLine = true
                 )
 
                 if (suggestions.isNotEmpty()) {
                     Spacer(modifier = Modifier.height(8.dp))
-                    Text(
+                    AppText(
                         text = "建议:",
-                        style = MaterialTheme.typography.labelSmall,
+                        style = LegadoTheme.typography.labelSmall,
                         modifier = Modifier.padding(bottom = 4.dp)
                     )
                     LazyRow(
@@ -61,7 +61,7 @@ fun TextListInputDialog(
                         items(suggestions) { suggestion ->
                             AssistChip(
                                 onClick = { text = suggestion },
-                                label = { Text(suggestion) }
+                                label = { AppText(suggestion) }
                             )
                         }
                     }
@@ -72,12 +72,12 @@ fun TextListInputDialog(
             TextButton(
                 onClick = { onConfirm(text) }
             ) {
-                Text(stringResource(android.R.string.ok))
+                AppText(stringResource(android.R.string.ok))
             }
         },
         dismissButton = {
             TextButton(onClick = onDismissRequest) {
-                Text(stringResource(android.R.string.cancel))
+                AppText(stringResource(android.R.string.cancel))
             }
         }
     )

+ 4 - 3
app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt

@@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -17,6 +16,8 @@ import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.text.AppText
 
 @Composable
 fun PillHeaderDivider(
@@ -40,9 +41,9 @@ fun PillHeaderDivider(
                 .background(dotColor)
         )
 
-        Text(
+        AppText(
             text = title,
-            style = MaterialTheme.typography.labelSmall,
+            style = LegadoTheme.typography.labelSmall,
             color = titleColor,
             modifier = Modifier.padding(horizontal = 12.dp),
             maxLines = 1

+ 6 - 5
app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt

@@ -20,7 +20,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -28,7 +27,9 @@ import androidx.compose.ui.graphics.vector.ImageVector
 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.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 
 enum class FilePickerSheetMode {
     DIR, FILE, EXPORT
@@ -56,9 +57,9 @@ fun FilePickerSheet(
                 .padding(horizontal = 16.dp, vertical = 8.dp),
             horizontalAlignment = Alignment.CenterHorizontally
         ) {
-            Text(
+            AppText(
                 text = title,
-                style = MaterialTheme.typography.titleMedium,
+                style = LegadoTheme.typography.titleMedium,
                 modifier = Modifier.padding(bottom = 20.dp)
             )
 
@@ -141,9 +142,9 @@ private fun RowScope.FilePickerOptionCard(
                 tint = MaterialTheme.colorScheme.primary
             )
             Spacer(modifier = Modifier.height(8.dp))
-            Text(
+            AppText(
                 text = text,
-                style = MaterialTheme.typography.labelMedium,
+                style = LegadoTheme.typography.labelMedium,
                 maxLines = 1
             )
         }

+ 10 - 9
app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt

@@ -25,7 +25,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButtonDefaults
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedIconButton
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -41,7 +40,9 @@ import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.widget.components.button.AnimatedActionButton
+import io.legado.app.ui.widget.components.text.AppText
 import java.time.LocalDate
 
 /**
@@ -60,7 +61,7 @@ fun HeatmapCalendarTopBar(
         horizontalArrangement = Arrangement.SpaceBetween,
         verticalAlignment = Alignment.CenterVertically
     ) {
-        Text("时间线", style = MaterialTheme.typography.titleMedium)
+        AppText("时间线", style = LegadoTheme.typography.titleMedium)
 
         Row(verticalAlignment = Alignment.CenterVertically) {
             AnimatedActionButton(
@@ -107,7 +108,7 @@ fun WeekdayLabelsColumn(
 
         labels.forEachIndexed { index, label ->
             if (index % 2 == 0) {
-                Text(
+                AppText(
                     text = label,
                     fontSize = 10.sp,
                     color = MaterialTheme.colorScheme.onSurfaceVariant,
@@ -170,7 +171,7 @@ fun NoEarlierDataIndicator(
             verticalArrangement = Arrangement.Center
         ) {
             "没有更早数据".forEach { char ->
-                Text(
+                AppText(
                     text = char.toString(),
                     fontSize = 9.sp,
                     lineHeight = 12.sp,
@@ -252,7 +253,7 @@ fun HeatmapWeekColumn(
 
         // 月份标签
         if (firstDayOfMonth != null) {
-            Text(
+            AppText(
                 text = "${firstDayOfMonth.monthValue}月",
                 fontSize = 10.sp,
                 color = MaterialTheme.colorScheme.onSurfaceVariant,
@@ -280,9 +281,9 @@ fun HeatmapLegend(
     ) {
         val legendUnit = if (mode == HeatmapMode.COUNT) "次" else "长"
 
-        Text(
+        AppText(
             "少($legendUnit)",
-            style = MaterialTheme.typography.bodySmall,
+            style = LegadoTheme.typography.bodySmall,
             color = Color.Gray
         )
 
@@ -298,9 +299,9 @@ fun HeatmapLegend(
             Spacer(modifier = Modifier.width(4.dp))
         }
 
-        Text(
+        AppText(
             "多($legendUnit)",
-            style = MaterialTheme.typography.bodySmall,
+            style = LegadoTheme.typography.bodySmall,
             color = Color.Gray
         )
     }

+ 37 - 0
app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt

@@ -0,0 +1,37 @@
+package io.legado.app.ui.widget.components.icon
+
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.Icon
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.theme.LocalContentColor
+import top.yukonga.miuix.kmp.basic.Icon as MiuixIcon
+
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
+@Composable
+fun AppIcon(
+    imageVector: ImageVector,
+    contentDescription: String?,
+    modifier: Modifier = Modifier,
+    tint: Color = LocalContentColor.current,
+) {
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        MiuixIcon(
+            imageVector = imageVector,
+            contentDescription = contentDescription,
+            modifier = modifier,
+            tint = tint
+        )
+    } else {
+        Icon(
+            imageVector = imageVector,
+            contentDescription = contentDescription,
+            modifier = modifier,
+            tint = tint
+        )
+    }
+}

+ 12 - 11
app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt

@@ -42,7 +42,6 @@ import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.OutlinedToggleButton
 import androidx.compose.material3.SnackbarHost
 import androidx.compose.material3.SnackbarHostState
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.material3.rememberModalBottomSheetState
@@ -59,9 +58,11 @@ import androidx.compose.ui.platform.LocalConfiguration
 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.AnimatedText
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.launch
 
 @Composable
@@ -77,25 +78,25 @@ fun SourceInputDialog(
 
     AlertDialog(
         onDismissRequest = onDismissRequest,
-        title = { Text(title) },
+        title = { AppText(title) },
         text = {
             Column {
                 OutlinedTextField(
                     value = text,
                     onValueChange = { text = it },
-                    label = { Text(hint) },
+                    label = { AppText(hint) },
                     modifier = Modifier.fillMaxWidth(),
                     maxLines = 5
                 )
 
                 if (historyValues.isNotEmpty()) {
                     Spacer(modifier = Modifier.height(8.dp))
-                    Text("历史记录:", style = MaterialTheme.typography.labelSmall)
+                    AppText("历史记录:", style = LegadoTheme.typography.labelSmall)
                     LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                         items(historyValues) { history ->
                             AssistChip(
                                 onClick = { text = history },
-                                label = { Text(history, maxLines = 1) }
+                                label = { AppText(history, maxLines = 1) }
                             )
                         }
                     }
@@ -105,11 +106,11 @@ fun SourceInputDialog(
         confirmButton = {
             OutlinedButton(
                 onClick = { if (text.isNotBlank()) onConfirm(text) }
-            ) { Text(stringResource(android.R.string.ok)) }
+            ) { AppText(stringResource(android.R.string.ok)) }
         },
         dismissButton = {
             TextButton(onClick = onDismissRequest) {
-                Text(stringResource(android.R.string.cancel))
+                AppText(stringResource(android.R.string.cancel))
             }
         }
     )
@@ -254,14 +255,14 @@ private fun ImportItemRow(
                 )
             },
             supportingContent = {
-                Text(
+                AppText(
                     text = when (status) {
                         ImportStatus.New -> "新增"
                         ImportStatus.Update -> "更新"
                         ImportStatus.Existing -> "已有"
                         ImportStatus.Error -> "错误"
                     },
-                    style = MaterialTheme.typography.labelMedium,
+                    style = LegadoTheme.typography.labelMedium,
                     color = when (status) {
                         ImportStatus.New -> MaterialTheme.colorScheme.primary
                         ImportStatus.Update -> MaterialTheme.colorScheme.secondary
@@ -315,12 +316,12 @@ fun ImportBottomBar(
             )
         }
         Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
-            OutlinedButton(onClick = onCancel) { Text("取消") }
+            OutlinedButton(onClick = onCancel) { AppText("取消") }
             Button(
                 enabled = selectedCount > 0,
                 onClick = onConfirm
             ) {
-                Text("导入")
+                AppText("导入")
             }
         }
     }

+ 11 - 24
app/src/main/java/io/legado/app/ui/widget/components/list/ListScaffold.kt

@@ -15,19 +15,11 @@ import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Add
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.FloatingActionButton
 import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset
 import androidx.compose.material3.Icon
-import androidx.compose.material3.PlainTooltip
 import androidx.compose.material3.SnackbarHost
 import androidx.compose.material3.SnackbarHostState
-import androidx.compose.material3.Text
-import androidx.compose.material3.TooltipAnchorPosition
-import androidx.compose.material3.TooltipBox
-import androidx.compose.material3.TooltipDefaults
-import androidx.compose.material3.TopAppBarScrollBehavior
 import androidx.compose.material3.animateFloatingActionButton
-import androidx.compose.material3.rememberTooltipState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
@@ -35,11 +27,13 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
+import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.SelectionActions
 import io.legado.app.ui.widget.components.SelectionBottomBar
 import io.legado.app.ui.widget.components.topbar.DynamicTopAppBar
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarScrollBehavior
 
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -52,28 +46,21 @@ fun <T> ListScaffold(
     onSearchQueryChange: (String) -> Unit,
     searchPlaceholder: String = "搜索...",
     topBarActions: @Composable RowScope.() -> Unit = {},
-    bottomContent: @Composable (ColumnScope.(TopAppBarScrollBehavior) -> Unit)? = null,
+    bottomContent: @Composable (ColumnScope.(GlassTopAppBarScrollBehavior) -> Unit)? = null,
     dropDownMenuContent: @Composable (ColumnScope.(dismiss: () -> Unit) -> Unit)? = null,
     selectionActions: SelectionActions? = null,
     onAddClick: (() -> Unit)? = null,
     floatingActionButton: @Composable () -> Unit = {
         onAddClick?.let { onClick ->
-            TooltipBox(
-                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
-                    TooltipAnchorPosition.Above
+            AppFloatingActionButton(
+                onClick = onClick,
+                modifier = Modifier.animateFloatingActionButton(
+                    visible = state.selectedIds.isEmpty(),
+                    alignment = Alignment.BottomEnd,
                 ),
-                tooltip = { PlainTooltip { Text("添加") } },
-                state = rememberTooltipState(),
+                tooltipText = "添加"
             ) {
-                FloatingActionButton(
-                    modifier = Modifier.animateFloatingActionButton(
-                        visible = state.selectedIds.isEmpty(),
-                        alignment = Alignment.BottomEnd,
-                    ),
-                    onClick = onClick
-                ) {
-                    Icon(Icons.Default.Add, contentDescription = "Add")
-                }
+                Icon(Icons.Default.Add, contentDescription = "Add")
             }
         }
     },

+ 2 - 1
app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt

@@ -25,6 +25,7 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.rememberOpaqueColorScheme
 
 @Composable
@@ -57,7 +58,7 @@ fun RoundDropdownMenuItem(
     ) {
         CompositionLocalProvider(
             LocalContentColor provides contentColor,
-            LocalTextStyle provides MaterialTheme.typography.labelLarge
+            LocalTextStyle provides LegadoTheme.typography.labelLarge
         ) {
             Row(
                 modifier = Modifier

+ 7 - 7
app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt

@@ -22,7 +22,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -37,6 +36,7 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
+import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.launch
 
 /**
@@ -84,7 +84,7 @@ fun <T> RuleEditSheet(
                     .verticalScroll(rememberScrollState())
             ) {
                 CenterAlignedTopAppBar(
-                    title = { Text(title) },
+                    title = { AppText(title) },
                     navigationIcon = {
                         IconButton(onClick = onDismissRequest) {
                             Icon(
@@ -99,7 +99,7 @@ fun <T> RuleEditSheet(
                         }
                         DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
                             DropdownMenuItem(
-                                text = { Text(stringResource(R.string.copy_rule)) },
+                                text = { AppText(stringResource(R.string.copy_rule)) },
                                 leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) },
                                 onClick = {
                                     onCopy(getCurrentEntity())
@@ -107,7 +107,7 @@ fun <T> RuleEditSheet(
                                 }
                             )
                             DropdownMenuItem(
-                                text = { Text(stringResource(R.string.paste_rule)) },
+                                text = { AppText(stringResource(R.string.paste_rule)) },
                                 leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
                                 onClick = {
                                     scope.launch {
@@ -136,20 +136,20 @@ fun <T> RuleEditSheet(
                         modifier = Modifier.fillMaxWidth(),
                         value = name,
                         onValueChange = { name = it },
-                        label = { Text(stringResource(R.string.name)) },
+                        label = { AppText(stringResource(R.string.name)) },
                         singleLine = true
                     )
                     OutlinedTextField(
                         modifier = Modifier.fillMaxWidth(),
                         value = rule1,
                         onValueChange = { rule1 = it },
-                        label = { Text(label1) }
+                        label = { AppText(label1) }
                     )
                     OutlinedTextField(
                         modifier = Modifier.fillMaxWidth(),
                         value = rule2,
                         onValueChange = { rule2 = it },
-                        label = { Text(label2) },
+                        label = { AppText(label2) },
                         minLines = 3
                     )
                 }

+ 15 - 27
app/src/main/java/io/legado/app/ui/widget/components/rules/RuleListScaffold.kt

@@ -10,20 +10,12 @@ import androidx.compose.material3.AlertDialog
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.FloatingActionButton
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
-import androidx.compose.material3.PlainTooltip
 import androidx.compose.material3.SnackbarHostState
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
-import androidx.compose.material3.TooltipAnchorPosition
-import androidx.compose.material3.TooltipBox
-import androidx.compose.material3.TooltipDefaults
-import androidx.compose.material3.TopAppBarScrollBehavior
 import androidx.compose.material3.animateFloatingActionButton
-import androidx.compose.material3.rememberTooltipState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -34,9 +26,12 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import io.legado.app.R
 import io.legado.app.ui.widget.components.ActionItem
+import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.SelectionActions
 import io.legado.app.ui.widget.components.list.ListScaffold
 import io.legado.app.ui.widget.components.list.ListUiState
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.ui.widget.components.topbar.GlassTopAppBarScrollBehavior
 
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -49,7 +44,7 @@ fun <T> RuleListScaffold(
     onSearchQueryChange: (String) -> Unit,
     searchPlaceholder: String = "搜索...",
     topBarActions: @Composable RowScope.() -> Unit = {},
-    bottomContent: @Composable (ColumnScope.(TopAppBarScrollBehavior) -> Unit)? = null,
+    bottomContent: @Composable (ColumnScope.(GlassTopAppBarScrollBehavior) -> Unit)? = null,
     dropDownMenuContent: (@Composable ColumnScope.(dismiss: () -> Unit) -> Unit)? = null,
     onClearSelection: () -> Unit,
     onSelectAll: () -> Unit,
@@ -59,22 +54,15 @@ fun <T> RuleListScaffold(
     onAddClick: (() -> Unit)? = null,
     floatingActionButton: @Composable () -> Unit = {
         onAddClick?.let { onClick ->
-            TooltipBox(
-                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
-                    TooltipAnchorPosition.Above
+            AppFloatingActionButton(
+                onClick = onClick,
+                modifier = Modifier.animateFloatingActionButton(
+                    visible = state.selectedIds.isEmpty(),
+                    alignment = Alignment.BottomEnd,
                 ),
-                tooltip = { PlainTooltip { Text("添加") } },
-                state = rememberTooltipState(),
+                tooltipText = "添加"
             ) {
-                FloatingActionButton(
-                    modifier = Modifier.animateFloatingActionButton(
-                        visible = state.selectedIds.isEmpty(),
-                        alignment = Alignment.BottomEnd,
-                    ),
-                    onClick = onClick
-                ) {
-                    Icon(Icons.Default.Add, contentDescription = "Add")
-                }
+                Icon(Icons.Default.Add, contentDescription = "Add")
             }
         }
     },
@@ -86,8 +74,8 @@ fun <T> RuleListScaffold(
     if (showDeleteConfirmDialog) {
         AlertDialog(
             onDismissRequest = { showDeleteConfirmDialog = false },
-            title = { Text(stringResource(R.string.delete)) },
-            text = { Text(stringResource(R.string.del_msg)) },
+            title = { AppText(stringResource(R.string.delete)) },
+            text = { AppText(stringResource(R.string.del_msg)) },
             confirmButton = {
                 OutlinedButton(
                     onClick = {
@@ -98,12 +86,12 @@ fun <T> RuleListScaffold(
                         contentColor = MaterialTheme.colorScheme.error
                     )
                 ) {
-                    Text(stringResource(R.string.ok))
+                    AppText(stringResource(R.string.ok))
                 }
             },
             dismissButton = {
                 TextButton(onClick = { showDeleteConfirmDialog = false }) {
-                    Text(stringResource(R.string.cancel))
+                    AppText(stringResource(R.string.cancel))
                 }
             }
         )

+ 30 - 16
app/src/main/java/io/legado/app/ui/widget/components/settingItem/ClickableSettingItem.kt

@@ -7,6 +7,10 @@ import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.basic.BasicComponentDefaults
+import top.yukonga.miuix.kmp.extra.SuperArrow
 
 @Composable
 fun ClickableSettingItem(
@@ -19,20 +23,30 @@ fun ClickableSettingItem(
     trailingContent: (@Composable () -> Unit)? = null,
     onClick: () -> Unit
 ) {
-    SettingItem(
-        modifier = modifier,
-        title = title,
-        description = description,
-        option = option,
-        imageVector = imageVector,
-        trailingContent = trailingContent ?: {
-            Icon(
-                imageVector = Icons.Default.ChevronRight,
-                contentDescription = null,
-                tint = MaterialTheme.colorScheme.onSurfaceVariant
-            )
-        },
-        onClick = onClick,
-        onLongClick = onLongClick
-    )
+    val composeEngine = LegadoTheme.composeEngine
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        SuperArrow(
+            title = title,
+            summary = description,
+            insideMargin = BasicComponentDefaults.InsideMargin,
+            onClick = onClick
+        )
+    } else {
+        SettingItem(
+            modifier = modifier,
+            title = title,
+            description = description,
+            option = option,
+            imageVector = imageVector,
+            trailingContent = trailingContent ?: {
+                Icon(
+                    imageVector = Icons.Default.ChevronRight,
+                    contentDescription = null,
+                    tint = MaterialTheme.colorScheme.onSurfaceVariant
+                )
+            },
+            onClick = onClick,
+            onLongClick = onLongClick
+        )
+    }
 }

+ 2 - 2
app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt

@@ -13,7 +13,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Slider
 import androidx.compose.material3.Switch
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
@@ -31,6 +30,7 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.ui.widget.components.button.SmallOutlinedIconButton
 import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -66,7 +66,7 @@ fun CompactDropdownSettingItem(
         dropdownMenu = { onDismiss ->
             displayEntries.forEachIndexed { index, display ->
                 RoundDropdownMenuItem(
-                    text = { Text(display) },
+                    text = { AppText(display) },
                     onClick = {
                         onValueChange(entryValues[index])
                         onDismiss()

+ 101 - 40
app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt

@@ -1,15 +1,17 @@
 package io.legado.app.ui.widget.components.settingItem
 
+import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.text.input.rememberTextFieldState
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Check
 import androidx.compose.material.icons.filled.Replay
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextField
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -21,7 +23,12 @@ 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.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.button.SmallTextButton
+import io.legado.app.ui.widget.components.text.AppText
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.basic.TextField as MiuixTextField
 
 @Composable
 fun InputSettingItem(
@@ -31,6 +38,7 @@ fun InputSettingItem(
     description: String? = null,
     onConfirm: (String) -> Unit
 ) {
+    // 1. 状态统一提升到外部,两套引擎共用
     var expanded by remember { mutableStateOf(false) }
     val state = rememberTextFieldState(initialText = value)
 
@@ -42,51 +50,104 @@ fun InputSettingItem(
         }
     }
 
-    SettingItem(
-        title = title,
-        description = description,
-        option = value,
-        expanded = expanded,
-        onExpandChange = { expanded = it },
-        expandContent = {
-            TextField(
-                state = state,
-                modifier = Modifier
-                    .fillMaxWidth()
-                    .heightIn(min = 48.dp),
-                label = { Text(stringResource(R.string.edit)) },
-                contentPadding = PaddingValues(
-                    top = 4.dp,
-                    bottom = 4.dp,
-                    start = 12.dp,
-                    end = 12.dp
-                ),
-                onKeyboardAction = {
-                    onConfirm(state.text.toString())
-                    expanded = false
-                }
+    val composeEngine = LegadoTheme.composeEngine
+
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        Column(modifier = Modifier.fillMaxWidth()) {
+            BasicComponent(
+                title = title,
+                summary = value,
+                onClick = { expanded = !expanded }
             )
 
-            Row(
-                modifier = Modifier.fillMaxWidth(),
-                horizontalArrangement = Arrangement.End
-            ) {
-                SmallTextButton(
-                    text = "默认",
-                    icon = Icons.Default.Replay,
-                    onClick = {
-                        state.edit { replace(0, length, defaultValue.toString()) }
+            AnimatedVisibility(visible = expanded) {
+                Column(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .padding(horizontal = 16.dp, vertical = 4.dp)
+                ) {
+                    MiuixTextField(
+                        state = state,
+                        modifier = Modifier.fillMaxWidth(),
+                        label = stringResource(R.string.edit),
+                        onKeyboardAction = {
+                            onConfirm(state.text.toString())
+                            expanded = false
+                        }
+                    )
+
+                    Row(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(top = 8.dp),
+                        horizontalArrangement = Arrangement.End
+                    ) {
+                        SmallTextButton(
+                            text = "默认",
+                            icon = Icons.Default.Replay,
+                            onClick = {
+                                state.edit { replace(0, length, defaultValue.toString()) }
+                            }
+                        )
+                        SmallTextButton(
+                            text = "确认",
+                            icon = Icons.Default.Check,
+                            onClick = {
+                                onConfirm(state.text.toString())
+                                expanded = false
+                            }
+                        )
                     }
-                )
-                SmallTextButton(
-                    text = "确认",
-                    icon = Icons.Default.Check,
-                    onClick = {
+                }
+            }
+        }
+    } else {
+        SettingItem(
+            title = title,
+            description = description,
+            option = value,
+            expanded = expanded,
+            onExpandChange = { expanded = it },
+            expandContent = {
+                TextField(
+                    state = state,
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .heightIn(min = 48.dp),
+                    label = { AppText(stringResource(R.string.edit)) },
+                    contentPadding = PaddingValues(
+                        top = 4.dp,
+                        bottom = 4.dp,
+                        start = 12.dp,
+                        end = 12.dp
+                    ),
+                    onKeyboardAction = {
                         onConfirm(state.text.toString())
                         expanded = false
                     }
                 )
+
+                Row(
+                    modifier = Modifier.fillMaxWidth(),
+                    horizontalArrangement = Arrangement.End
+                ) {
+                    SmallTextButton(
+                        text = "默认",
+                        icon = Icons.Default.Replay,
+                        onClick = {
+                            state.edit { replace(0, length, defaultValue.toString()) }
+                        }
+                    )
+                    SmallTextButton(
+                        text = "确认",
+                        icon = Icons.Default.Check,
+                        onClick = {
+                            onConfirm(state.text.toString())
+                            expanded = false
+                        }
+                    )
+                }
             }
-        }
-    )
+        )
+    }
 }

+ 61 - 28
app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt

@@ -4,12 +4,16 @@ import androidx.compose.foundation.layout.size
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Check
 import androidx.compose.material3.Icon
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.text.AppText
+import top.yukonga.miuix.kmp.basic.SpinnerEntry
+import top.yukonga.miuix.kmp.extra.SuperSpinner
 
 @Composable
 fun DropdownListSettingItem(
@@ -21,33 +25,62 @@ fun DropdownListSettingItem(
     imageVector: ImageVector? = null,
     onValueChange: (String) -> Unit
 ) {
-    val currentEntry = displayEntries.getOrNull(entryValues.indexOf(selectedValue)) ?: selectedValue
+    val composeEngine = LegadoTheme.composeEngine
 
-    SettingItem(
-        title = title,
-        description = description,
-        option = currentEntry,
-        imageVector = imageVector,
-        onClick = { },
-        dropdownMenu = { onDismiss ->
-            displayEntries.forEachIndexed { index, display ->
-                RoundDropdownMenuItem(
-                    text = { Text(display) },
-                    onClick = {
-                        onValueChange(entryValues[index])
-                        onDismiss()
-                    },
-                    trailingIcon = if (selectedValue == entryValues[index]) {
-                        {
-                            Icon(
-                                Icons.Default.Check,
-                                contentDescription = null,
-                                modifier = Modifier.size(18.dp)
-                            )
-                        }
-                    } else null
-                )
-            }
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        val selectedIndex = entryValues.indexOf(selectedValue).coerceAtLeast(0)
+        val spinnerItems = displayEntries.map { display ->
+            SpinnerEntry(title = display)
         }
-    )
+
+        SuperSpinner(
+            title = title,
+            summary = description,
+            items = spinnerItems,
+            selectedIndex = selectedIndex,
+            startAction = imageVector?.let { icon ->
+                {
+                    Icon(
+                        imageVector = icon,
+                        contentDescription = null
+                    )
+                }
+            },
+            onSelectedIndexChange = { index ->
+                onValueChange(entryValues[index])
+            }
+        )
+    } else {
+
+        val currentEntry =
+            displayEntries.getOrNull(entryValues.indexOf(selectedValue)) ?: selectedValue
+
+        SettingItem(
+            title = title,
+            description = description,
+            option = currentEntry,
+            imageVector = imageVector,
+            onClick = { },
+            dropdownMenu = { onDismiss ->
+                displayEntries.forEachIndexed { index, display ->
+                    RoundDropdownMenuItem(
+                        text = { AppText(display) },
+                        onClick = {
+                            onValueChange(entryValues[index])
+                            onDismiss()
+                        },
+                        trailingIcon = if (selectedValue == entryValues[index]) {
+                            {
+                                Icon(
+                                    Icons.Default.Check,
+                                    contentDescription = null,
+                                    modifier = Modifier.size(18.dp)
+                                )
+                            }
+                        } else null
+                    )
+                }
+            }
+        )
+    }
 }

+ 10 - 9
app/src/main/java/io/legado/app/ui/widget/components/settingItem/SettingItem.kt

@@ -19,7 +19,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.ListItem
 import androidx.compose.material3.ListItemDefaults
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -33,8 +32,10 @@ import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.graphics.painter.Painter
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
-import io.legado.app.ui.widget.components.card.GlassCard
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.card.SettingCard
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
+import io.legado.app.ui.widget.components.text.AppText
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
@@ -59,7 +60,7 @@ fun SettingItem(
     var showMenu by remember { mutableStateOf(false) }
     val isExpandable = expandContent != null && onExpandChange != null
 
-    GlassCard(
+    SettingCard(
         modifier = modifier
             .fillMaxWidth(),
         shape = shape,
@@ -101,25 +102,25 @@ fun SettingItem(
                     }
                 } else null,
                 headlineContent = {
-                    Text(
+                    AppText(
                         text = title,
-                        style = MaterialTheme.typography.titleMedium
+                        style = LegadoTheme.typography.titleMedium
                     )
                 },
                 supportingContent = if (description != null || option != null) {
                     {
                         Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
                             description?.let {
-                                Text(
+                                AppText(
                                     it,
-                                    style = MaterialTheme.typography.bodySmallEmphasized,
+                                    style = LegadoTheme.typography.bodySmallEmphasized,
                                     color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
                                 )
                             }
                             option?.let {
-                                Text(
+                                AppText(
                                     it,
-                                    style = MaterialTheme.typography.labelMediumEmphasized,
+                                    style = LegadoTheme.typography.labelMediumEmphasized,
                                     color = MaterialTheme.colorScheme.primary
                                 )
                             }

+ 179 - 68
app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt

@@ -1,12 +1,15 @@
 package io.legado.app.ui.widget.components.settingItem
 
 import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.foundation.text.input.TextFieldLineLimits
@@ -17,7 +20,6 @@ import androidx.compose.material.icons.filled.LinearScale
 import androidx.compose.material.icons.filled.RestartAlt
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Slider
-import androidx.compose.material3.Text
 import androidx.compose.material3.TextField
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -29,7 +31,13 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.button.SmallTextButton
+import io.legado.app.ui.widget.components.text.AppText
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.basic.Slider as MiuixSlider
+import top.yukonga.miuix.kmp.basic.TextField as MiuixTextField
 
 @Composable
 fun SliderSettingItem(
@@ -45,85 +53,188 @@ fun SliderSettingItem(
 
     var expanded by remember { mutableStateOf(false) }
     var isInputMode by remember { mutableStateOf(false) }
-    var inputText by remember { mutableStateOf(value.toInt().toString()) }
     val textFieldState = rememberTextFieldState(initialText = value.toInt().toString())
 
-    SettingItem(
-        title = title,
-        color = color ?: MaterialTheme.colorScheme.surfaceContainerLow,
-        option = description,
-        expanded = expanded,
-        onExpandChange = { expanded = it },
-        expandContent = {
-            Row(verticalAlignment = Alignment.CenterVertically) {
-                AnimatedContent(
-                    targetState = isInputMode,
-                    label = "input_slider_switch"
-                ) { targetInputMode ->
-                    if (targetInputMode) {
-                        TextField(
-                            state = textFieldState,
-                            lineLimits = TextFieldLineLimits.SingleLine,
-                            label = { Text("输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})") },
-                            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
-                            modifier = Modifier
-                                .fillMaxWidth()
-                                .heightIn(min = 48.dp),
-                            contentPadding = PaddingValues(
-                                top = 4.dp,
-                                bottom = 4.dp,
-                                start = 12.dp,
-                                end = 12.dp
-                            ),
-                            inputTransformation = {
-                                val newText = asCharSequence().toString()
-                                newText.toFloatOrNull()?.let { num ->
-                                    onValueChange(
-                                        num.coerceIn(
-                                            valueRange.start,
-                                            valueRange.endInclusive
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+
+        Column(modifier = Modifier.fillMaxWidth()) {
+            BasicComponent(
+                title = title,
+                summary = description,
+                onClick = { expanded = !expanded }
+            )
+
+            AnimatedVisibility(visible = expanded) {
+                Column(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .padding(horizontal = 16.dp, vertical = 8.dp)
+                ) {
+                    AnimatedContent(
+                        targetState = isInputMode,
+                        label = "input_slider_switch"
+                    ) { targetInputMode ->
+                        if (targetInputMode) {
+                            MiuixTextField(
+                                state = textFieldState,
+                                lineLimits = TextFieldLineLimits.SingleLine,
+                                label = "输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})",
+                                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
+                                modifier = Modifier.fillMaxWidth(),
+                                inputTransformation = {
+                                    val newText = asCharSequence().toString()
+                                    newText.toFloatOrNull()?.let { num ->
+                                        onValueChange(
+                                            num.coerceIn(
+                                                valueRange.start,
+                                                valueRange.endInclusive
+                                            )
+                                        )
+                                    }
+                                }
+                            )
+                        } else {
+                            MiuixSlider(
+                                value = value,
+                                onValueChange = {
+                                    onValueChange(it)
+                                    textFieldState.edit {
+                                        replace(
+                                            0,
+                                            length,
+                                            it.toInt().toString()
                                         )
+                                    }
+                                },
+                                valueRange = valueRange,
+                                steps = steps,
+                                modifier = Modifier.fillMaxWidth()
+                            )
+                        }
+                    }
+
+                    Row(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(top = 16.dp),
+                        horizontalArrangement = Arrangement.End
+                    ) {
+                        SmallTextButton(
+                            text = if (isInputMode) "滑块" else "输入",
+                            icon = if (isInputMode) Icons.Default.LinearScale else Icons.Default.Edit,
+                            onClick = { isInputMode = !isInputMode }
+                        )
+
+                        Spacer(Modifier.width(8.dp))
+
+                        SmallTextButton(
+                            text = "默认",
+                            icon = Icons.Default.RestartAlt,
+                            onClick = {
+                                onValueChange(defaultValue)
+                                textFieldState.edit {
+                                    replace(
+                                        0,
+                                        length,
+                                        defaultValue.toInt().toString()
                                     )
                                 }
                             }
                         )
-                    } else {
-                        Slider(
-                            value = value,
-                            onValueChange = {
-                                onValueChange(it)
-                                textFieldState.edit { replace(0, length, it.toInt().toString()) }
-                            },
-                            valueRange = valueRange,
-                            steps = steps,
-                            modifier = Modifier
-                                .fillMaxWidth()
-                        )
                     }
                 }
             }
+        }
 
-            Row(
-                modifier = Modifier.fillMaxWidth(),
-                horizontalArrangement = Arrangement.End
-            ) {
-                SmallTextButton(
-                    text = if (isInputMode) "滑块" else "输入",
-                    icon = if (isInputMode) Icons.Default.LinearScale else Icons.Default.Edit,
-                    onClick = { isInputMode = !isInputMode }
-                )
+    } else {
+        SettingItem(
+            title = title,
+            color = color ?: MaterialTheme.colorScheme.surfaceContainerLow,
+            option = description,
+            expanded = expanded,
+            onExpandChange = { expanded = it },
+            expandContent = {
+                Row(verticalAlignment = Alignment.CenterVertically) {
+                    AnimatedContent(
+                        targetState = isInputMode,
+                        label = "input_slider_switch"
+                    ) { targetInputMode ->
+                        if (targetInputMode) {
+                            TextField(
+                                state = textFieldState,
+                                lineLimits = TextFieldLineLimits.SingleLine,
+                                label = { AppText("输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})") },
+                                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
+                                modifier = Modifier
+                                    .fillMaxWidth()
+                                    .heightIn(min = 48.dp),
+                                contentPadding = PaddingValues(
+                                    top = 4.dp,
+                                    bottom = 4.dp,
+                                    start = 12.dp,
+                                    end = 12.dp
+                                ),
+                                inputTransformation = {
+                                    val newText = asCharSequence().toString()
+                                    newText.toFloatOrNull()?.let { num ->
+                                        onValueChange(
+                                            num.coerceIn(
+                                                valueRange.start,
+                                                valueRange.endInclusive
+                                            )
+                                        )
+                                    }
+                                }
+                            )
+                        } else {
+                            Slider(
+                                value = value,
+                                onValueChange = {
+                                    onValueChange(it)
+                                    textFieldState.edit {
+                                        replace(
+                                            0,
+                                            length,
+                                            it.toInt().toString()
+                                        )
+                                    }
+                                },
+                                valueRange = valueRange,
+                                steps = steps,
+                                modifier = Modifier.fillMaxWidth()
+                            )
+                        }
+                    }
+                }
 
-                Spacer(Modifier.width(8.dp))
+                Row(
+                    modifier = Modifier.fillMaxWidth(),
+                    horizontalArrangement = Arrangement.End
+                ) {
+                    SmallTextButton(
+                        text = if (isInputMode) "滑块" else "输入",
+                        icon = if (isInputMode) Icons.Default.LinearScale else Icons.Default.Edit,
+                        onClick = { isInputMode = !isInputMode }
+                    )
 
-                SmallTextButton(
-                    text = "默认",
-                    icon = Icons.Default.RestartAlt,
-                    onClick = {
-                        onValueChange(defaultValue)
-                        textFieldState.edit { replace(0, length, defaultValue.toInt().toString()) }
-                    }
-                )
+                    Spacer(Modifier.width(8.dp))
+
+                    SmallTextButton(
+                        text = "默认",
+                        icon = Icons.Default.RestartAlt,
+                        onClick = {
+                            onValueChange(defaultValue)
+                            textFieldState.edit {
+                                replace(
+                                    0,
+                                    length,
+                                    defaultValue.toInt().toString()
+                                )
+                            }
+                        }
+                    )
+                }
             }
-        }
-    )
+        )
+    }
 }

+ 41 - 14
app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt

@@ -3,7 +3,12 @@ package io.legado.app.ui.widget.components.settingItem
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
-import io.legado.app.ui.widget.components.IconSwitch
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.AdaptiveSwitch
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.basic.Switch
+
 
 @Composable
 fun SwitchSettingItem(
@@ -15,18 +20,40 @@ fun SwitchSettingItem(
     enabled: Boolean = true,
     onCheckedChange: (Boolean) -> Unit
 ) {
-    SettingItem(
-        title = title,
-        description = description,
-        imageVector = imageVector,
-        color = color,
-        onClick = { if (enabled) onCheckedChange(!checked) },
-        trailingContent = {
-            IconSwitch(
-                checked = checked,
-                onCheckedChange = onCheckedChange,
-                enabled = enabled
-            )
+    val composeEngine = LegadoTheme.composeEngine
+
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        val toggleAction = {
+            if (enabled) onCheckedChange(!checked)
         }
-    )
+
+        BasicComponent(
+            title = title,
+            summary = description,
+            enabled = enabled,
+            onClick = toggleAction,
+            endActions = {
+                Switch(
+                    checked = checked,
+                    onCheckedChange = onCheckedChange,
+                    enabled = enabled
+                )
+            }
+        )
+    } else {
+        SettingItem(
+            title = title,
+            description = description,
+            imageVector = imageVector,
+            color = color,
+            onClick = { if (enabled) onCheckedChange(!checked) },
+            trailingContent = {
+                AdaptiveSwitch(
+                    checked = checked,
+                    onCheckedChange = onCheckedChange,
+                    enabled = enabled
+                )
+            }
+        )
+    }
 }

+ 63 - 0
app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt

@@ -0,0 +1,63 @@
+package io.legado.app.ui.widget.components.tabRow
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.PrimaryScrollableTabRow
+import androidx.compose.material3.Tab
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.widget.components.text.AppText
+import top.yukonga.miuix.kmp.basic.TabRowDefaults
+import top.yukonga.miuix.kmp.basic.TabRowWithContour
+
+@Composable
+fun AdaptiveTabRow(
+    tabTitles: List<String>,
+    selectedTabIndex: Int,
+    onTabSelected: (Int) -> Unit,
+    modifier: Modifier = Modifier
+) {
+    val composeEngine = LegadoTheme.composeEngine
+
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        TabRowWithContour(
+            tabs = tabTitles,
+            selectedTabIndex = selectedTabIndex,
+            onTabSelected = onTabSelected,
+            modifier = modifier.padding(start = 12.dp),
+            colors = TabRowDefaults.tabRowColors(
+                backgroundColor = Color.Transparent
+            )
+        )
+    } else {
+        PrimaryScrollableTabRow(
+            selectedTabIndex = selectedTabIndex,
+            edgePadding = 0.dp,
+            divider = { },
+            containerColor = Color.Transparent,
+            minTabWidth = 0.dp,
+            modifier = modifier
+        ) {
+            tabTitles.forEachIndexed { index, title ->
+                Tab(
+                    selected = selectedTabIndex == index,
+                    onClick = { onTabSelected(index) },
+                    text = {
+                        AppText(
+                            text = title,
+                            maxLines = 1,
+                            overflow = TextOverflow.Ellipsis,
+                            modifier = Modifier.padding(horizontal = 8.dp),
+                            color = MaterialTheme.colorScheme.onSurfaceVariant
+                        )
+                    }
+                )
+            }
+        }
+    }
+}

+ 150 - 0
app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt

@@ -0,0 +1,150 @@
+package io.legado.app.ui.widget.components.text
+
+
+import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextDecoration
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.TextUnit
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.basic.Text as MiuixText
+
+@Composable
+fun AppText(
+    text: String,
+    modifier: Modifier = Modifier,
+    color: Color = Color.Unspecified,
+    fontSize: TextUnit = TextUnit.Unspecified,
+    fontStyle: FontStyle? = null,
+    fontWeight: FontWeight? = null,
+    fontFamily: FontFamily? = null,
+    letterSpacing: TextUnit = TextUnit.Unspecified,
+    textDecoration: TextDecoration? = null,
+    textAlign: TextAlign? = null,
+    lineHeight: TextUnit = TextUnit.Unspecified,
+    overflow: TextOverflow = TextOverflow.Clip,
+    softWrap: Boolean = true,
+    maxLines: Int = Int.MAX_VALUE,
+    minLines: Int = 1,
+    onTextLayout: ((TextLayoutResult) -> Unit)? = null,
+    style: TextStyle? = null,
+) {
+
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        MiuixText(
+            text = text,
+            modifier = modifier,
+            color = color,
+            fontSize = fontSize,
+            fontStyle = fontStyle,
+            fontWeight = fontWeight,
+            fontFamily = fontFamily,
+            letterSpacing = letterSpacing,
+            textDecoration = textDecoration,
+            textAlign = textAlign,
+            lineHeight = lineHeight,
+            overflow = overflow,
+            softWrap = softWrap,
+            maxLines = maxLines,
+            minLines = minLines,
+            onTextLayout = onTextLayout,
+            style = style ?: MiuixTheme.textStyles.main
+        )
+    } else {
+        Text(
+            text = text,
+            modifier = modifier,
+            color = color,
+            fontSize = fontSize,
+            fontStyle = fontStyle,
+            fontWeight = fontWeight,
+            fontFamily = fontFamily,
+            letterSpacing = letterSpacing,
+            textDecoration = textDecoration,
+            textAlign = textAlign,
+            lineHeight = lineHeight,
+            overflow = overflow,
+            softWrap = softWrap,
+            maxLines = maxLines,
+            minLines = minLines,
+            onTextLayout = onTextLayout ?: {},
+            style = style ?: LocalTextStyle.current
+        )
+    }
+}
+
+@Composable
+fun AppText(
+    text: AnnotatedString,
+    modifier: Modifier = Modifier,
+    color: Color = Color.Unspecified,
+    fontSize: TextUnit = TextUnit.Unspecified,
+    fontStyle: FontStyle? = null,
+    fontWeight: FontWeight? = null,
+    fontFamily: FontFamily? = null,
+    letterSpacing: TextUnit = TextUnit.Unspecified,
+    textDecoration: TextDecoration? = null,
+    textAlign: TextAlign? = null,
+    lineHeight: TextUnit = TextUnit.Unspecified,
+    overflow: TextOverflow = TextOverflow.Clip,
+    softWrap: Boolean = true,
+    maxLines: Int = Int.MAX_VALUE,
+    minLines: Int = 1,
+    onTextLayout: ((TextLayoutResult) -> Unit)? = null,
+    style: TextStyle? = null,
+) {
+
+    if (ThemeResolver.isMiuixEngine(composeEngine)) {
+        MiuixText(
+            text = text,
+            modifier = modifier,
+            color = color,
+            fontSize = fontSize,
+            fontStyle = fontStyle,
+            fontWeight = fontWeight,
+            fontFamily = fontFamily,
+            letterSpacing = letterSpacing,
+            textDecoration = textDecoration,
+            textAlign = textAlign,
+            lineHeight = lineHeight,
+            overflow = overflow,
+            softWrap = softWrap,
+            maxLines = maxLines,
+            minLines = minLines,
+            onTextLayout = onTextLayout ?: {},
+            style = style ?: MiuixTheme.textStyles.main
+        )
+    } else {
+        Text(
+            text = text,
+            modifier = modifier,
+            color = color,
+            fontSize = fontSize,
+            fontStyle = fontStyle,
+            fontWeight = fontWeight,
+            fontFamily = fontFamily,
+            letterSpacing = letterSpacing,
+            textDecoration = textDecoration,
+            textAlign = textAlign,
+            lineHeight = lineHeight,
+            overflow = overflow,
+            softWrap = softWrap,
+            maxLines = maxLines,
+            minLines = minLines,
+            onTextLayout = onTextLayout ?: {},
+            style = style ?: LocalTextStyle.current
+        )
+    }
+}

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