From 01fb34a1bd08e2b7ea37af5814f130c8e32f00c7 Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:28:46 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 5 + .../java/io/legado/app/data/dao/BookDao.kt | 14 + .../io/legado/app/ui/about/AboutScreen.kt | 18 +- .../io/legado/app/ui/about/AppLogSheet.kt | 21 +- .../app/ui/book/bookmark/AllBookmarkScreen.kt | 16 +- .../app/ui/book/explore/ExploreShowScreen.kt | 73 +++-- .../app/ui/book/group/GroupEditSheet.kt | 14 +- .../ui/book/import/remote/RemoteBookScreen.kt | 65 ++--- .../ui/book/info/edit/BookInfoEditScreen.kt | 22 +- .../ui/book/readRecord/ReadRecordScreen.kt | 103 ++++--- .../book/searchContent/SearchContentScreen.kt | 35 ++- .../io/legado/app/ui/book/toc/TocScreen.kt | 47 ++-- .../app/ui/book/toc/rule/TxtRuleScreen.kt | 18 +- .../legado/app/ui/config/ConfigNavScreen.kt | 7 +- .../config/backupConfig/BackupConfigScreen.kt | 44 ++- .../config/coverConfig/CoverConfigScreen.kt | 7 +- .../ui/config/coverConfig/CoverManageSheet.kt | 7 +- .../coverConfig/CoverRuleConfigSheet.kt | 18 +- .../otherConfig/CheckSourceBottomSheet.kt | 11 +- .../DirectLinkUploadBottomSheet.kt | 33 +-- .../config/otherConfig/OtherConfigScreen.kt | 41 +-- .../app/ui/config/readConfig/PageKeySheet.kt | 19 +- .../ui/config/readConfig/ReadConfigScreen.kt | 9 +- .../themeConfig/BackgroundImageManageSheet.kt | 7 +- .../themeConfig/LauncherIconPickerSheet.kt | 7 +- .../app/ui/config/themeConfig/ThemeConfig.kt | 3 + .../config/themeConfig/ThemeConfigScreen.kt | 36 ++- .../ui/config/themeConfig/ThemeListDialog.kt | 32 ++- .../app/ui/dict/rule/DictRuleEditSheet.kt | 14 +- .../legado/app/ui/dict/rule/DictRuleScreen.kt | 18 +- .../io/legado/app/ui/main/MainActivity.kt | 8 +- .../io/legado/app/ui/main/MainDestination.kt | 53 ++-- .../java/io/legado/app/ui/main/MainScreen.kt | 116 ++------ .../legado/app/ui/main/bookshelf/BookItem.kt | 33 +-- .../app/ui/main/bookshelf/BookShelfItem.kt | 4 + .../ui/main/bookshelf/BookshelfConfigSheet.kt | 7 +- .../app/ui/main/bookshelf/BookshelfScreen.kt | 68 ++--- .../app/ui/main/bookshelf/GroupManageSheet.kt | 7 +- .../app/ui/main/explore/ExploreScreen.kt | 69 ++--- .../java/io/legado/app/ui/main/my/MyScreen.kt | 147 ++++++---- .../io/legado/app/ui/main/rss/RssScreen.kt | 31 +-- .../app/ui/replace/ReplaceRuleScreen.kt | 76 ++---- .../app/ui/replace/edit/ReplaceEditScreen.kt | 58 ++-- .../ui/rss/favorites/RssFavoritesScreen.kt | 14 +- .../ui/rss/source/manage/RssSourceScreen.kt | 42 +-- .../app/ui/rss/subscription/RuleSubScreen.kt | 24 +- .../io/legado/app/ui/theme/AdaptivePadding.kt | 19 ++ .../java/io/legado/app/ui/theme/AppTheme.kt | 77 +++++- .../java/io/legado/app/ui/theme/HazeStyle.kt | 8 +- .../io/legado/app/ui/theme/LegadoTheme.kt | 85 ++++++ .../io/legado/app/ui/theme/ThemeResolver.kt | 12 + .../java/io/legado/app/ui/theme/Typography.kt | 44 +++ .../app/ui/theme/hazeStyle/HazeLegado.kt | 48 ++++ .../legado/app/ui/widget/CollapsibleHeader.kt | 11 +- .../app/ui/widget/components/AnimatedText.kt | 6 +- .../components/AppFloatingActionButton.kt | 56 ++++ .../ui/widget/components/AppNavigationBar.kt | 93 +++++++ .../app/ui/widget/components/AppScaffold.kt | 113 ++++---- .../ui/widget/components/EmptyMessageView.kt | 4 +- .../GlassMediumFlexibleTopAppBar.kt | 113 -------- .../components/GroupManageBottomSheet.kt | 9 +- .../app/ui/widget/components/IconSwitch.kt | 34 +++ .../ui/widget/components/SearchBarSection.kt | 4 +- .../widget/components/SelectionBottomBar.kt | 6 +- .../widget/components/SplicedColumnGroup.kt | 41 +-- .../components/bookmark/BookmarkEditSheet.kt | 23 +- .../components/bookmark/BookmarkItem.kt | 15 +- .../widget/components/button/AlertButton.kt | 4 +- .../components/button/AnimatedActionButton.kt | 8 +- .../components/button/AnimatedTextButton.kt | 4 +- .../components/button/MiuixBackButton.kt | 57 ++++ .../components/button/SmallIconButton.kt | 47 ++-- .../components/button/SmallTextButton.kt | 7 +- .../widget/components/button/TopBarButton.kt | 131 +++++---- .../ui/widget/components/card/GlassCard.kt | 140 +++++++--- .../components/card/SelectionItemCard.kt | 67 +++-- .../ui/widget/components/card/SettingCard.kt | 75 ++++++ .../app/ui/widget/components/card/TextCard.kt | 26 +- .../components/checkBox/CheckboxItem.kt | 7 +- .../widget/components/cover/BookshelfCover.kt | 22 +- .../components/dialog/ColorPickerSheet.kt | 15 +- .../components/dialog/TextListInputDialog.kt | 18 +- .../components/divider/PillHeaderDivider.kt | 7 +- .../components/filePicker/FilePickerSheet.kt | 11 +- .../heatmap/HeatmapCalendarComponents.kt | 19 +- .../app/ui/widget/components/icon/AppIcon.kt | 37 +++ .../importComponents/ImportComponents.kt | 23 +- .../ui/widget/components/list/ListScaffold.kt | 35 +-- .../menuItem/RoundDropdownMenuItem.kt | 3 +- .../widget/components/rules/RuleEditSheet.kt | 14 +- .../components/rules/RuleListScaffold.kt | 42 ++- .../settingItem/ClickableSettingItem.kt | 46 ++-- .../settingItem/CompactSettingItems.kt | 4 +- .../settingItem/InputSettingItem.kt | 141 +++++++--- .../components/settingItem/ListSettingItem.kt | 89 ++++-- .../components/settingItem/SettingItem.kt | 19 +- .../settingItem/SliderSettingItem.kt | 253 +++++++++++++----- .../settingItem/SwitchSettingItem.kt | 55 +++- .../components/tabRow/AdaptiveTabRow.kt | 63 +++++ .../app/ui/widget/components/text/AppText.kt | 150 +++++++++++ .../ui/widget/components/title/SmallTitle.kt | 33 +++ .../components/topbar/DynamicTopAppBar.kt | 159 +++++------ .../topbar/GlassMediumFlexibleTopAppBar.kt | 178 ++++++++++++ .../components/topbar/MiuixScrollBehavior.kt | 36 +++ app/version.properties | 4 +- gradle/libs.versions.toml | 22 +- 106 files changed, 2889 insertions(+), 1524 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt create mode 100644 app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt create mode 100644 app/src/main/java/io/legado/app/ui/theme/Typography.kt create mode 100644 app/src/main/java/io/legado/app/ui/theme/hazeStyle/HazeLegado.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/AppFloatingActionButton.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt delete mode 100644 app/src/main/java/io/legado/app/ui/widget/components/GlassMediumFlexibleTopAppBar.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/card/SettingCard.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/title/SmallTitle.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/topbar/MiuixScrollBehavior.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cb9419239..3bee712c9 100644 --- a/app/build.gradle.kts +++ b/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) } diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 00cff7098..7a3179040 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/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, diff --git a/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt b/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt index 51b148e92..59f0f1bb7 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt +++ b/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() diff --git a/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt b/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt index 2e727ae07..ba3706e15 100644 --- a/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt +++ b/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) ) } diff --git a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt b/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt index ed2f086dd..025d24f01 100644 --- a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt index 2f5c164d5..12706b01c 100644 --- a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt index c22a618c3..472ce06ee 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt +++ b/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)) } } } diff --git a/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt b/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt index 756d2d97a..3f0588aee 100644 --- a/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt index f84aea298..d7798d3c0 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt b/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt index e2fec7f18..3263ec78d 100644 --- a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt index 948144d6d..813129e82 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt index 09c46d2bd..b1ede3b7d 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt +++ b/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() 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 ) } diff --git a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt index 30738041b..dd17674c4 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt +++ b/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) } ) diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigNavScreen.kt b/app/src/main/java/io/legado/app/ui/config/ConfigNavScreen.kt index 89db7857f..4b4b1c099 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigNavScreen.kt +++ b/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) diff --git a/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt index ac34f94a4..e261c97d0 100644 --- a/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt +++ b/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)) } } ) diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt index 5aee17431..829901a72 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt +++ b/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) diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt index 52c6298ca..7f28526ad 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt +++ b/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) ) diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt index 974f3f42f..56b5ceb74 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt +++ b/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)) } } } diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt index 790e95878..6be30bb24 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt +++ b/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)) } } } diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt index 7014ae1f5..ac5fdd38c 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt +++ b/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)) } } ) } diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt index d6c6f6426..a86a882fa 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt +++ b/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)) } } ) diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt index 6e64cba0b..fe143678f 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt +++ b/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)) } } } diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt index e5565d4f5..ebe4e064e 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt +++ b/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) diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt index f10ebfe91..2f19eb534 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt +++ b/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) ) diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt index 26e1ab766..e273691ec 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt +++ b/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) ) diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt index 9337cd8d8..2902d9631 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt +++ b/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") diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt index 097287985..1cc290be3 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt index da96e5864..13594b5d6 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt +++ b/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)) } } ) diff --git a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt index e3c30be93..5d9f98ced 100644 --- a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt index 5ef5ec458..e157fd51d 100644 --- a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt +++ b/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) } ) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 6168adef4..e7778a926 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/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( diff --git a/app/src/main/java/io/legado/app/ui/main/MainDestination.kt b/app/src/main/java/io/legado/app/ui/main/MainDestination.kt index 69569d2b0..7db8fd46c 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainDestination.kt +++ b/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) } -} +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt index 4f9398bcb..5ed27fa30 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt +++ b/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() }, 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 { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookItem.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookItem.kt index 3bdeb0c58..a443f1955 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookItem.kt +++ b/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) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookShelfItem.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookShelfItem.kt index a588eb524..e7717278d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookShelfItem.kt +++ b/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) } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt index b9195137f..10c5bc5cd 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt +++ b/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) ) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt index 98e872661..76dcafcce 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt +++ b/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(); 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(); 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,33 +322,19 @@ fun BookshelfScreen( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { - PrimaryScrollableTabRow( - selectedTabIndex = selectedTabIndex, - edgePadding = 0.dp, - divider = { }, - containerColor = Color.Transparent, - minTabWidth = 0.dp, - 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 - ) - } - ) - } + val tabTitles = remember(uiState.groups) { + uiState.groups.map { it.groupName } } + AdaptiveTabRow( + tabTitles = tabTitles, + selectedTabIndex = selectedTabIndex, + onTabSelected = { index -> + scope.launch { pagerState.animateScrollToPage(index) } + }, + modifier = Modifier.weight(1f) + ) + if (BookshelfConfig.shouldShowExpandButton) { Box(modifier = Modifier.padding(end = 16.dp)) { SmallOutlinedIconToggleButton( @@ -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 ) } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt index 765a58bbf..7149b5f13 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt index 562e0ebbb..f624b8934 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt b/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt index d23e1a50b..f752583fa 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt +++ b/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)) + } + ) + } + } + } +} diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt index f86a76602..3a25954cf 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt +++ b/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, diff --git a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt index 1990471ea..3cb2cf8f2 100644 --- a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt +++ b/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() } ) } diff --git a/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt b/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt index cd8164437..5e473d408 100644 --- a/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt +++ b/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) ) } diff --git a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt index c2808857b..3cc61f0e2 100644 --- a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt +++ b/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() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt index 0c69d89a6..ee194858c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt +++ b/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") } ) } diff --git a/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt b/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt index 58c10ffdb..0da339c1e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt +++ b/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)) } } ) diff --git a/app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt b/app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt new file mode 100644 index 000000000..64233c4dd --- /dev/null +++ b/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) +} diff --git a/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt b/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt index 76a21a88a..cac926249 100644 --- a/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt +++ b/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() + } + } + } } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/theme/HazeStyle.kt b/app/src/main/java/io/legado/app/ui/theme/HazeStyle.kt index f5091207b..3fa41bc07 100644 --- a/app/src/main/java/io/legado/app/ui/theme/HazeStyle.kt +++ b/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() ) } diff --git a/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt b/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt new file mode 100644 index 000000000..292c2d277 --- /dev/null +++ b/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 { 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 + +} diff --git a/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt b/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt index 9db56a725..226185e92 100644 --- a/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/theme/Typography.kt b/app/src/main/java/io/legado/app/ui/theme/Typography.kt new file mode 100644 index 000000000..5352a507d --- /dev/null +++ b/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) + ) +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/theme/hazeStyle/HazeLegado.kt b/app/src/main/java/io/legado/app/ui/theme/hazeStyle/HazeLegado.kt new file mode 100644 index 000000000..20b5acb54 --- /dev/null +++ b/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), + ), + ) +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt b/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt index 292fe1b7f..70d3ec548 100644 --- a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt +++ b/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, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt b/app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt index 1a71821d2..cfa21f308 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt +++ b/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, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppFloatingActionButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppFloatingActionButton.kt new file mode 100644 index 000000000..5c72e0a93 --- /dev/null +++ b/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 + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt new file mode 100644 index 000000000..eb9eda5f4 --- /dev/null +++ b/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 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt index 696556ded..24b2dbffe 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt +++ b/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 + } + + 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) + } + } } } } - - 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) - } - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt b/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt index a5de35e2d..66df4fb29 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt +++ b/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, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/GlassMediumFlexibleTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/GlassMediumFlexibleTopAppBar.kt deleted file mode 100644 index bd6d1432f..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/components/GlassMediumFlexibleTopAppBar.kt +++ /dev/null @@ -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)) - } -} diff --git a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt index 120e28b43..8d91e4feb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt +++ b/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, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/IconSwitch.kt b/app/src/main/java/io/legado/app/ui/widget/components/IconSwitch.kt index 305d58fa7..c34eb4fef 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/IconSwitch.kt +++ b/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( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt b/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt index f1ffd61c5..d62ac9726 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt +++ b/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( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/SelectionBottomBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/SelectionBottomBar.kt index 0f3b2da5e..953ee3b0f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/SelectionBottomBar.kt +++ b/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( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/SplicedColumnGroup.kt b/app/src/main/java/io/legado/app/ui/widget/components/SplicedColumnGroup.kt index 739d4e0a4..0157b5aac 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/SplicedColumnGroup.kt +++ b/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() diff --git a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt index 2e0b12866..832f97f4a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt +++ b/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("取消") } } ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt index aeb9f423a..cab80e10f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/AlertButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/AlertButton.kt index e6f18d3fb..fd97db5a7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/AlertButton.kt +++ b/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) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedActionButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedActionButton.kt index 261984e98..5b93a9c81 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedActionButton.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedTextButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedTextButton.kt index b2df9fc52..e0bd24c2e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/AnimatedTextButton.kt +++ b/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) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt new file mode 100644 index 000000000..27093ad7e --- /dev/null +++ b/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 + ) + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt index 99bfe8f41..6d1a51ad0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt index e26cd9f38..4dc24e991 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt +++ b/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 ) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt index d7c3e822d..f6251874d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt +++ b/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 - ) { - - AnimatedContent( - targetState = checked, - label = "IconAnimation" - ) { targetChecked -> - AnimatedIcon( - modifier = Modifier.size(20.dp), - imageVector = if (targetChecked) iconChecked else iconUnchecked, - contentDescription = null - ) + 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 } - - AnimatedVisibility( - visible = showText + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center ) { - Text( - text = if (lastCheckedState) activeText else inactiveText, - style = MaterialTheme.typography.labelMedium, - modifier = Modifier.padding(start = 8.dp), - maxLines = 1, - softWrap = false - ) + + AnimatedContent( + targetState = checked, + label = "IconAnimation" + ) { targetChecked -> + AnimatedIcon( + modifier = Modifier.size(20.dp), + imageVector = if (targetChecked) iconChecked else iconUnchecked, + contentDescription = null + ) + } + + AnimatedVisibility( + visible = showText + ) { + AppText( + text = if (lastCheckedState) activeText else inactiveText, + style = LegadoTheme.typography.labelMedium, + modifier = Modifier.padding(start = 8.dp), + maxLines = 1, + softWrap = false + ) + } } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt index 43de6eedf..e8b781948 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt @@ -4,14 +4,79 @@ 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 +private fun BaseCard( + 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, + alpha: Float = 1f, + content: @Composable ColumnScope.() -> Unit +) { + 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, + cornerRadius = cornerRadius, + onClick = onClick, + content = content, + colors = colors + ) + } else { + 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 @@ -19,43 +84,50 @@ fun GlassCard( 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, content: @Composable ColumnScope.() -> Unit ) { - val containerAlpha = ThemeConfig.containerOpacity / 100f + BaseCard( + modifier = modifier, + onClick = onClick, + shape = shape, + cornerRadius = cornerRadius, + containerColor = containerColor, + contentColor = contentColor, + elevation = elevation, + border = border, + alpha = ThemeConfig.containerOpacity / 100f, + content = content + ) +} - val baseColors = colors ?: CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.secondaryContainer, - contentColor = MaterialTheme.colorScheme.onSecondaryContainer +@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 ) - - 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 - ) - } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt index 14373157c..f8db95733 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/SettingCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/SettingCard.kt new file mode 100644 index 000000000..bc4953351 --- /dev/null +++ b/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 + ) + } + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt index cacfc9f1e..86abfd33c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt +++ b/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( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/checkBox/CheckboxItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/checkBox/CheckboxItem.kt index f341faed5..1bfb8c85d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/checkBox/CheckboxItem.kt +++ b/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) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt b/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt index ed6817b86..ec7f0be47 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt index 0c124e227..26390c39c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt +++ b/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)) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/dialog/TextListInputDialog.kt b/app/src/main/java/io/legado/app/ui/widget/components/dialog/TextListInputDialog.kt index 1444facbf..1bb7fddd9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/dialog/TextListInputDialog.kt +++ b/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)) } } ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt index f44574dc0..e189ed31c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt index 735069bba..0ed751d4d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt b/app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt index 20815a1e3..8c75dac87 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt new file mode 100644 index 000000000..a2f0270e2 --- /dev/null +++ b/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 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt b/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt index 18caaf8f1..2c72a0c8e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt +++ b/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("导入") } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/list/ListScaffold.kt b/app/src/main/java/io/legado/app/ui/widget/components/list/ListScaffold.kt index de0e53644..e1805234b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/list/ListScaffold.kt +++ b/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 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") } } }, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt index 560b6b4d7..8e20a0531 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt index 0a528c2ea..e2cb8063a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt +++ b/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 RuleEditSheet( .verticalScroll(rememberScrollState()) ) { CenterAlignedTopAppBar( - title = { Text(title) }, + title = { AppText(title) }, navigationIcon = { IconButton(onClick = onDismissRequest) { Icon( @@ -99,7 +99,7 @@ fun 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 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 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 ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleListScaffold.kt b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleListScaffold.kt index 78931b93d..48b588124 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleListScaffold.kt +++ b/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 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 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 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 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)) } } ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ClickableSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ClickableSettingItem.kt index cb77972a6..219d6dfa6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ClickableSettingItem.kt +++ b/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 + ) + } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt index dd360dfa8..e5e83b6f6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt +++ b/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() diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt index a6b62e88e..63ad5d893 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt +++ b/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 + } + ) + } } - } - ) + ) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt index 724b40289..532302557 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt +++ b/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 + ) + } + } + ) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SettingItem.kt index 727a075e1..884239099 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SettingItem.kt +++ b/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 ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt index d1f3a5b39..a1a08a3ad 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt +++ b/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 } - ) - - Spacer(Modifier.width(8.dp)) - - SmallTextButton( - text = "默认", - icon = Icons.Default.RestartAlt, - onClick = { - onValueChange(defaultValue) - textFieldState.edit { replace(0, length, defaultValue.toInt().toString()) } - } - ) - } } - ) + + } 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() + ) + } + } + } + + 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 } + ) + + Spacer(Modifier.width(8.dp)) + + SmallTextButton( + text = "默认", + icon = Icons.Default.RestartAlt, + onClick = { + onValueChange(defaultValue) + textFieldState.edit { + replace( + 0, + length, + defaultValue.toInt().toString() + ) + } + } + ) + } + } + ) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt index 09a3d33bf..f0e458f20 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt +++ b/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 + ) + } + ) + } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt b/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt new file mode 100644 index 000000000..c9afdf567 --- /dev/null +++ b/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, + 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 + ) + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt b/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt new file mode 100644 index 000000000..51a1735e5 --- /dev/null +++ b/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 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/title/SmallTitle.kt b/app/src/main/java/io/legado/app/ui/widget/components/title/SmallTitle.kt new file mode 100644 index 000000000..b6f5f4fa8 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/title/SmallTitle.kt @@ -0,0 +1,33 @@ +package io.legado.app.ui.widget.components.title + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +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 top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.Text as MiuixText + +@Composable +fun AdaptiveTitle( + text: String, + modifier: Modifier = Modifier +) { + val composeEngine = LegadoTheme.composeEngine + if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixText( + modifier = modifier, + text = text, + style = MiuixTheme.textStyles.subtitle, + color = MiuixTheme.colorScheme.onBackgroundVariant, + ) + } else { + Text( + text = text, + style = LegadoTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.primary, + modifier = modifier + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt index dca7f7d9a..1d4048933 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt @@ -1,14 +1,12 @@ package io.legado.app.ui.widget.components.topbar import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.animateColorAsState import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth @@ -20,8 +18,8 @@ import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -30,11 +28,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.lerp import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.text.style.TextOverflow -import io.legado.app.ui.widget.components.AdaptiveAnimatedText import io.legado.app.ui.widget.components.AnimatedTextLine -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.TopBarActionButton import io.legado.app.ui.widget.components.button.TopbarNavigationButton @@ -48,7 +42,7 @@ fun DynamicTopAppBar( title: String, subtitle: String? = null, state: ListUiState, - scrollBehavior: TopAppBarScrollBehavior, + scrollBehavior: GlassTopAppBarScrollBehavior, onBackClick: (() -> Unit)? = null, onSearchToggle: (Boolean) -> Unit, onSearchQueryChange: (String) -> Unit, @@ -59,7 +53,7 @@ fun DynamicTopAppBar( onClearSelection: () -> Unit, topBarActions: @Composable RowScope.() -> Unit = {}, dropDownMenuContent: @Composable (ColumnScope.(dismiss: () -> Unit) -> Unit)? = null, - bottomContent: @Composable (ColumnScope.(TopAppBarScrollBehavior) -> Unit)? = null + bottomContent: @Composable (ColumnScope.(GlassTopAppBarScrollBehavior) -> Unit)? = null ) { var showMenu by remember { mutableStateOf(false) } val isSelecting = state.selectedIds.isNotEmpty() @@ -67,93 +61,84 @@ fun DynamicTopAppBar( val containerColor = GlassTopAppBarDefaults.containerColor() val scrolledColor = GlassTopAppBarDefaults.scrolledContainerColor() - val collapsedFraction = scrollBehavior.state.collapsedFraction + val animatedColor by remember(scrollBehavior, containerColor, scrolledColor) { + derivedStateOf { + lerp(containerColor, scrolledColor, scrollBehavior.collapsedFraction) + } + } - val animatedColor by animateColorAsState( - targetValue = lerp(containerColor, scrolledColor, collapsedFraction), - label = "TopBarContainerColor" - ) - - Column( + GlassMediumFlexibleTopAppBar( modifier = Modifier .fillMaxWidth() - .background(animatedColor) - ) { - GlassMediumFlexibleTopAppBar( - title = { - val titleText = when { - state.isLoading -> "请稍后..." - isSelecting -> "已选择 ${state.selectedIds.size}/${state.items.size}" - else -> title - } - AdaptiveAnimatedText( - text = titleText, - useCharMode = isSelecting || state.isLoading, - maxLines = 1, - overflow = TextOverflow.Ellipsis + .background(animatedColor), + title = when { + state.isLoading -> "请稍后..." + isSelecting -> "已选择 ${state.selectedIds.size}/${state.items.size}" + else -> title + }, + useCharMode = isSelecting || state.isLoading, + subtitle = subtitle?.let { + { AnimatedTextLine(text = it) } + }, + navigationIcon = { + if (isSelecting || onBackClick != null) { + TopbarNavigationButton( + onClick = { if (isSelecting) onClearSelection() else onBackClick?.invoke() }, + imageVector = if (isSelecting) Icons.Default.Close else Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = if (isSelecting) "取消选择" else "返回" + ) + } + }, + actions = { + if (!isSelecting) { + TopBarActionButton( + onClick = { onSearchToggle(!state.isSearch) }, + imageVector = Icons.Default.Search, + contentDescription = "搜索" ) - }, - subtitle = subtitle?.let { - { AnimatedTextLine(text = it) } - }, - navigationIcon = { - if (isSelecting || onBackClick != null) { - TopbarNavigationButton( - onClick = { if (isSelecting) onClearSelection() else onBackClick?.invoke() }, - imageVector = if (isSelecting) Icons.Default.Close else Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = if (isSelecting) "取消选择" else "返回" - ) - } - }, - actions = { - if (!isSelecting) { - TopBarActionButton( - onClick = { onSearchToggle(!state.isSearch) }, - imageVector = Icons.Default.Search, - contentDescription = "搜索" - ) - topBarActions() + topBarActions() - dropDownMenuContent?.let { content -> - Box { - TopBarActionButton( - onClick = { showMenu = true }, - imageVector = Icons.Default.MoreVert, - contentDescription = "更多" - ) - RoundDropdownMenu( - expanded = showMenu, - onDismissRequest = { showMenu = false } - ) { dismiss -> - content(dismiss) - } + dropDownMenuContent?.let { content -> + Box { + TopBarActionButton( + onClick = { showMenu = true }, + imageVector = Icons.Default.MoreVert, + contentDescription = "更多" + ) + RoundDropdownMenu( + expanded = showMenu, + onDismissRequest = { showMenu = false } + ) { dismiss -> + content(dismiss) } } } - }, - scrollBehavior = scrollBehavior, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.Transparent, - scrolledContainerColor = Color.Transparent - ) - ) + } + }, + scrollBehavior = scrollBehavior, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Transparent, + scrolledContainerColor = Color.Transparent + ), + bottomContent = { + AnimatedVisibility( + visible = state.isSearch && !isSelecting, + enter = expandVertically() + fadeIn(), + exit = shrinkVertically() + fadeOut() + ) { + SearchBarSection( + query = state.searchKey, + onQueryChange = onSearchQueryChange, + placeholder = searchPlaceholder, + leadingIcon = { Icon(searchLeadingIcon, null) }, + trailingIcon = searchTrailingIcon, + dropdownMenu = searchDropdownMenu + ) + } - AnimatedVisibility( - visible = state.isSearch && !isSelecting, - enter = expandVertically() + fadeIn(), - exit = shrinkVertically() + fadeOut() - ) { - SearchBarSection( - query = state.searchKey, - onQueryChange = onSearchQueryChange, - placeholder = searchPlaceholder, - leadingIcon = { Icon(searchLeadingIcon, null) }, - trailingIcon = searchTrailingIcon, - dropdownMenu = searchDropdownMenu - ) + bottomContent?.invoke(this, scrollBehavior) } - - bottomContent?.invoke(this, scrollBehavior) - } + ) } + diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt new file mode 100644 index 000000000..e06f0d6da --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt @@ -0,0 +1,178 @@ +package io.legado.app.ui.widget.components.topbar + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +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.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextOverflow +import io.legado.app.ui.config.themeConfig.ThemeConfig +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.responsiveHazeEffect +import io.legado.app.ui.widget.components.AdaptiveAnimatedText +import io.legado.app.ui.widget.components.GlassDefaults +import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior +import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.TopAppBar as MiuixTopAppBar + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun GlassMediumFlexibleTopAppBar( + title: String, + modifier: Modifier = Modifier, + useCharMode: Boolean = false, + subtitle: (@Composable () -> Unit)? = null, + scrollBehavior: GlassTopAppBarScrollBehavior? = null, + navigationIcon: @Composable () -> Unit = {}, + actions: @Composable RowScope.() -> Unit = {}, + colors: TopAppBarColors = GlassTopAppBarDefaults.glassColors(), + bottomContent: @Composable (ColumnScope.() -> Unit)? = null +) { + + val hazeState = LocalHazeState.current + val finalModifier = if (hazeState != null) { + modifier.responsiveHazeEffect(state = hazeState) + } else { + modifier + } + + val composeEngine = LegadoTheme.composeEngine + + Column(modifier = finalModifier) { + when { + ThemeResolver.isMiuixEngine(composeEngine) -> { + MiuixTopAppBar( + modifier = Modifier, + title = title, + navigationIcon = navigationIcon, + actions = actions, + color = GlassTopAppBarDefaults.getMiuixAppBarColor(), + scrollBehavior = (scrollBehavior as? MiuixGlassScrollBehavior)?.miuixBehavior + ) + } + + else -> { + if (ThemeConfig.useFlexibleTopAppBar) { + MediumFlexibleTopAppBar( + modifier = Modifier, + title = { + AdaptiveAnimatedText( + text = title, + useCharMode = useCharMode, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + }, + subtitle = subtitle, + navigationIcon = navigationIcon, + actions = actions, + scrollBehavior = (scrollBehavior as? M3GlassScrollBehavior)?.m3Behavior, + colors = colors + ) + } else { + TopAppBar( + modifier = Modifier, + title = { + AdaptiveAnimatedText( + text = title, + useCharMode = useCharMode, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + }, + navigationIcon = navigationIcon, + actions = actions, + scrollBehavior = (scrollBehavior as? M3GlassScrollBehavior)?.m3Behavior, + colors = colors + ) + } + } + } + bottomContent?.invoke(this) + } +} + +object GlassTopAppBarDefaults { + + @Composable + fun getMiuixAppBarColor() = GlassDefaults.glassColor( + noBlurColor = MiuixTheme.colorScheme.surface, + blurAlpha = GlassDefaults.TransparentAlpha + ) + + @OptIn(ExperimentalMaterial3Api::class) + @Composable + fun defaultScrollBehavior(): GlassTopAppBarScrollBehavior { + val composeEngine = ThemeConfig.composeEngine + + return if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixGlassScrollBehavior(MiuixScrollBehavior()) + } else if (ThemeConfig.useFlexibleTopAppBar) { + M3GlassScrollBehavior(TopAppBarDefaults.exitUntilCollapsedScrollBehavior()) + } else { + M3GlassScrollBehavior(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)) + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/MiuixScrollBehavior.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/MiuixScrollBehavior.kt new file mode 100644 index 000000000..f393d8b8e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/MiuixScrollBehavior.kt @@ -0,0 +1,36 @@ +package io.legado.app.ui.widget.components.topbar + +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TopAppBarScrollBehavior +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import top.yukonga.miuix.kmp.basic.ScrollBehavior + + +interface GlassTopAppBarScrollBehavior { + // 滚动连接器 + val nestedScrollConnection: NestedScrollConnection + + // 折叠进度:0f 表示完全展开,1f 表示完全折叠。 + val collapsedFraction: Float +} + +@OptIn(ExperimentalMaterial3Api::class) +class M3GlassScrollBehavior( + val m3Behavior: TopAppBarScrollBehavior +) : GlassTopAppBarScrollBehavior { + override val nestedScrollConnection: NestedScrollConnection + get() = m3Behavior.nestedScrollConnection + + override val collapsedFraction: Float + get() = m3Behavior.state.collapsedFraction +} + +class MiuixGlassScrollBehavior( + val miuixBehavior: ScrollBehavior +) : GlassTopAppBarScrollBehavior { + override val nestedScrollConnection: NestedScrollConnection + get() = miuixBehavior.nestedScrollConnection + + override val collapsedFraction: Float + get() = miuixBehavior.state.collapsedFraction +} \ No newline at end of file diff --git a/app/version.properties b/app/version.properties index a5149387f..910d3613b 100644 --- a/app/version.properties +++ b/app/version.properties @@ -1,5 +1,5 @@ VERSION_MAJOR=3 VERSION_MINOR=26 -VERSION_PATCH=9 -VERSION_SUFFIX=0 +VERSION_PATCH=10 +VERSION_SUFFIX=1 # 1 = Pre, 0 = Release \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 275c1ac83..8dadc71c4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,14 +4,14 @@ accompanistWebview = "0.36.0" adaptive = "1.3.0-alpha09" adaptiveLayout = "1.3.0-alpha09" adaptiveNavigation = "1.3.0-alpha09" -animation = "1.10.1" -biometric = "1.2.0" +animation = "1.10.6" +biometric = "1.4.0-alpha06" coilCompose = "2.7.0" -composeBom = "2026.03.00" +composeBom = "2026.03.01" constraintlayoutCompose = "1.1.1" coreSplashscreen = "1.2.0" datastorePreferences = "1.2.1" -foundation = "1.10.5" +foundation = "1.10.6" kotlin = "2.3.10" kotlinxSerialization = "1.10.0" kotlinxCoroutinesAndroid = "1.10.2" @@ -83,6 +83,10 @@ biometricKtx = "1.1.0" reorderable = "3.0.0" haze = "1.7.2" +timber = "5.0.1" +miuix = "0.8.8" +backdrop = "1.0.6" +capsule = "2.1.3" [libraries] accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanistWebview" } @@ -239,6 +243,16 @@ androidx-biometric-ktx = { group = "androidx.biometric", name = "biometric-ktx", reorderable = { module = "sh.calvin.reorderable:reorderable", version.ref = "reorderable" } +# log +timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } + +# miuix +miuix = { group = "top.yukonga.miuix.kmp", name = "miuix-android", version.ref = "miuix" } +miuix-icons = { group = "top.yukonga.miuix.kmp", name = "miuix-icons-android", version.ref = "miuix" } + +capsule = { module = "io.github.kyant0:capsule", version.ref = "capsule" } +backdrop = { module = "io.github.kyant0:backdrop", version.ref = "backdrop" } + [bundles] coroutines = ["kotlinx-coroutines-core", "kotlinx-coroutines-android"] androidTest = ["androidx-espresso-core", "androidx-junit", "androidx-runner"] From 733312fe23176928edb711909bf5c893137d6a35 Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Tue, 31 Mar 2026 07:55:21 +0800 Subject: [PATCH 2/3] =?UTF-8?q?[=E4=BC=98=E5=8C=96]=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=8E=A7=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/ui/book/explore/ExploreShowScreen.kt | 1 - .../config/themeConfig/ThemeConfigScreen.kt | 115 +++++++++++------- .../java/io/legado/app/ui/main/MainScreen.kt | 6 +- .../app/ui/main/explore/ExploreScreen.kt | 63 +++++++--- .../widget/components/{icon => }/AppIcon.kt | 24 +++- .../app/ui/widget/components/AppScaffold.kt | 7 +- .../app/ui/widget/components/card/TextCard.kt | 34 ++++-- .../components/topbar/DynamicTopAppBar.kt | 20 +-- .../topbar/GlassMediumFlexibleTopAppBar.kt | 46 +++++-- app/src/main/res/values-zh-rCN/arrays.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values/array_values.xml | 1 - app/src/main/res/values/arrays.xml | 1 - app/version.properties | 2 +- 14 files changed, 206 insertions(+), 117 deletions(-) rename app/src/main/java/io/legado/app/ui/widget/components/{icon => }/AppIcon.kt (60%) diff --git a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt index 12706b01c..3f494c6f4 100644 --- a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt @@ -295,7 +295,6 @@ fun ExploreShowScreen( state = hazeState ), title = selectedTitle ?: title, - colors = GlassTopAppBarDefaults.glassColors(), navigationIcon = { TopbarNavigationButton(onClick = onBack) }, diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt index 1cc290be3..a3163414a 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt @@ -137,23 +137,28 @@ fun ThemeConfigScreen( .verticalScroll(rememberScrollState()) .padding(16.dp) ) { + val composeEngine = remember { ThemeConfig.composeEngine } + val isMiuixEngine = + remember(composeEngine) { ThemeResolver.isMiuixEngine(composeEngine) } val isDarkTheme = when (selectedThemeMode) { "1" -> false "2" -> true else -> isSystemInDarkTheme() } - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxWidth() - ) { - ThemeCard( - context = context, - value = selectedTheme, - isDark = isDarkTheme, - isAmoled = ThemeConfig.isPureBlack, - paletteStyle = ThemeConfig.paletteStyle - ) + if (!isMiuixEngine) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxWidth() + ) { + ThemeCard( + context = context, + value = selectedTheme, + isDark = isDarkTheme, + isAmoled = ThemeConfig.isPureBlack, + paletteStyle = ThemeConfig.paletteStyle + ) + } } Spacer(modifier = Modifier.height(16.dp)) @@ -165,46 +170,62 @@ fun ThemeConfigScreen( } SplicedColumnGroup(title = stringResource(R.string.theme)) { - ThemeModeSelector( - selectedMode = selectedThemeMode, - onModeSelected = { mode -> - selectedThemeMode = mode - ThemeConfig.themeMode = mode - OldThemeConfig.applyDayNight(context) - } - ) + if (isMiuixEngine) { + DropdownListSettingItem( + title = stringResource(R.string.theme_mode), + selectedValue = selectedThemeMode, + displayEntries = stringArrayResource(R.array.theme_mode), + entryValues = stringArrayResource(R.array.theme_mode_v), + onValueChange = { mode -> + selectedThemeMode = mode + ThemeConfig.themeMode = mode + OldThemeConfig.applyDayNight(context) + } + ) + } else { + ThemeModeSelector( + selectedMode = selectedThemeMode, + onModeSelected = { mode -> + selectedThemeMode = mode + ThemeConfig.themeMode = mode + OldThemeConfig.applyDayNight(context) + } + ) + } - Spacer(modifier = Modifier.height(16.dp)) + if (!isMiuixEngine) { + Spacer(modifier = Modifier.height(16.dp)) - ThemeColorSelector( - context = context, - themes = themes, - selectedTheme = selectedTheme, - isDark = isDarkTheme, - isAmoled = ThemeConfig.isPureBlack, - paletteStyle = ThemeConfig.paletteStyle, - onThemeSelected = { theme -> - if (theme == "13") { - val hasLightBg = !ThemeConfig.bgImageLight.isNullOrEmpty() - val hasDarkBg = !ThemeConfig.bgImageDark.isNullOrEmpty() - if (!hasLightBg || !hasDarkBg) { - context.toastOnUi(R.string.transparent_theme_alarm) - return@ThemeColorSelector + ThemeColorSelector( + context = context, + themes = themes, + selectedTheme = selectedTheme, + isDark = isDarkTheme, + isAmoled = ThemeConfig.isPureBlack, + paletteStyle = ThemeConfig.paletteStyle, + onThemeSelected = { theme -> + if (theme == "13") { + val hasLightBg = !ThemeConfig.bgImageLight.isNullOrEmpty() + val hasDarkBg = !ThemeConfig.bgImageDark.isNullOrEmpty() + if (!hasLightBg || !hasDarkBg) { + context.toastOnUi(R.string.transparent_theme_alarm) + return@ThemeColorSelector + } else { + AppConfig.containerOpacity = 0 + } + } + val oldTheme = selectedTheme + selectedTheme = theme + ThemeConfig.appTheme = theme + val isDynamicSwitch = (oldTheme == "12" || theme == "12") + if (isDynamicSwitch) { + showRestartDialog = true } else { - AppConfig.containerOpacity = 0 + postEvent(EventBus.RECREATE, "") } } - val oldTheme = selectedTheme - selectedTheme = theme - ThemeConfig.appTheme = theme - val isDynamicSwitch = (oldTheme == "12" || theme == "12") - if (isDynamicSwitch) { - showRestartDialog = true - } else { - postEvent(EventBus.RECREATE, "") - } - } - ) + ) + } } SplicedColumnGroup { @@ -240,7 +261,7 @@ fun ThemeConfigScreen( R.string.font_scale_summary, AppContextWrapper.getFontScale(context) ), - value = fontScaleValue.value, + value = fontScaleValue.floatValue, defaultValue = 10f, valueRange = 8f..16f, steps = 7, diff --git a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt index 5ed27fa30..2465c7f1d 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt @@ -254,7 +254,11 @@ fun MainScreen( labelString = stringResource(destination.labelId), miuixIcon = if (selected) destination.miuixSelectedIcon else destination.miuixIcon, m3Icon = { - if (selected) destination.m3SelectedIcon else destination.m3Icon + NavigationIcon( + destination = destination, + selected = selected, + upBooksCount = uiState.upBooksCount + ) }, m3IndicatorColor = GlassDefaults.glassColor( noBlurColor = MaterialTheme.colorScheme.secondaryContainer, diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt index f624b8934..9be3376af 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt @@ -42,7 +42,6 @@ import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedCard import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -142,6 +141,8 @@ fun ExploreScreen( } } + val composeEngine = ThemeResolver.isMiuixEngine(composeEngine) + ListScaffold( title = stringResource(R.string.discovery), state = uiState, @@ -201,7 +202,8 @@ fun ExploreScreen( } }, onRefresh = { viewModel.refreshExploreKinds(item) }, - onDelete = { sourceToDelete = item } + onDelete = { sourceToDelete = item }, + isMiuix = composeEngine ) } @@ -232,7 +234,8 @@ fun ExploreScreen( putExtra("exploreUrl", kind.url) } } - } + }, + isMiuix = composeEngine ) } @@ -268,7 +271,8 @@ fun ExploreScreen( uiState.items.indexOfFirst { it.bookSourceUrl == item.bookSourceUrl } if (index >= 0) listState.animateScrollToItem(index) } - } + }, + isMiuix = composeEngine ) } } @@ -345,25 +349,25 @@ fun ExploreSourceHeader( onLogin: () -> Unit, onRefresh: () -> Unit, onDelete: () -> Unit, + isMiuix: Boolean, ) { 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) - if (composeEngine) MiuixTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.secondaryContainer + if (isMiuix) MiuixTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.secondaryContainer else - if (composeEngine) MiuixTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.surfaceContainerLow, + if (isMiuix) 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 + if (isMiuix) MiuixTheme.colorScheme.primary else MaterialTheme.colorScheme.primary else - if (composeEngine) MiuixTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurface, + if (isMiuix) MiuixTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurface, animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing), label = "CardColor" ) @@ -461,11 +465,11 @@ fun ExploreSourceHeader( @Composable fun ExploreStickyCard( item: BookSourcePart, - onClick: () -> Unit + onClick: () -> Unit, + isMiuix: Boolean, ) { TextCard( text = item.bookSourceName, - backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh, textStyle = LegadoTheme.typography.labelLarge, horizontalPadding = 8.dp, verticalPadding = 6.dp, @@ -478,8 +482,29 @@ fun ExploreKindItem( kind: ExploreKind, isClickable: Boolean, onClick: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + isMiuix: Boolean, ) { + val color = if (isMiuix) + MiuixTheme.colorScheme.surfaceContainer + else + MaterialTheme.colorScheme.secondaryContainer + + val contentColor = if (isMiuix) + MiuixTheme.colorScheme.onSurface + else + MaterialTheme.colorScheme.secondary + + val unClickBackColor = if (isMiuix) + MiuixTheme.colorScheme.surfaceContainer + else + MaterialTheme.colorScheme.surface + + val unClickColor = if (isMiuix) + MiuixTheme.colorScheme.disabledOnSurface + else + MaterialTheme.colorScheme.primary + CompositionLocalProvider( LocalMinimumInteractiveComponentSize provides Dp.Unspecified ) { @@ -490,19 +515,19 @@ fun ExploreKindItem( GlassCard( onClick = onClick, shape = shape, - containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.6f), - contentColor = MaterialTheme.colorScheme.onSecondaryContainer, + containerColor = color.copy(alpha = 0.6f), + contentColor = contentColor, modifier = modifier ) { KindText(kind) } } else { - OutlinedCard( + GlassCard( shape = shape, - colors = CardDefaults.outlinedCardColors( - contentColor = MaterialTheme.colorScheme.primary - ), - modifier = modifier + containerColor = unClickBackColor.copy(alpha = 0.6f), + contentColor = unClickColor, + modifier = modifier, + border = CardDefaults.outlinedCardBorder() ) { KindText(kind) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt similarity index 60% rename from app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt rename to app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt index a2f0270e2..4c6d5b557 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt @@ -1,6 +1,6 @@ -package io.legado.app.ui.widget.components.icon +package io.legado.app.ui.widget.components + -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -8,18 +8,20 @@ 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 androidx.compose.material3.LocalContentColor as MaterialLocalContentColor import top.yukonga.miuix.kmp.basic.Icon as MiuixIcon +import top.yukonga.miuix.kmp.theme.LocalContentColor as MiuixLocalContentColor -@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun AppIcon( imageVector: ImageVector, contentDescription: String?, modifier: Modifier = Modifier, - tint: Color = LocalContentColor.current, + tint: Color = currentContentColor(), ) { - if (ThemeResolver.isMiuixEngine(composeEngine)) { + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + + if (isMiuix) { MiuixIcon( imageVector = imageVector, contentDescription = contentDescription, @@ -34,4 +36,14 @@ fun AppIcon( tint = tint ) } +} + +@Composable +fun currentContentColor(): Color { + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + return if (isMiuix) { + MiuixLocalContentColor.current + } else { + MaterialLocalContentColor.current + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt index 24b2dbffe..a692bf6e9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/AppScaffold.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FabPosition -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.ScaffoldDefaults import androidx.compose.material3.contentColorFor @@ -35,7 +34,7 @@ fun AppScaffold( snackbarHost: @Composable () -> Unit = {}, floatingActionButton: @Composable () -> Unit = {}, floatingActionButtonPosition: FabPosition = FabPosition.End, - contentColor: Color = contentColorFor(MaterialTheme.colorScheme.background), + contentColor: Color = contentColorFor(MiuixTheme.colorScheme.surface), contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets, content: @Composable (PaddingValues) -> Unit ) { @@ -56,7 +55,9 @@ fun AppScaffold( MiuixTheme.colorScheme.surface } - CompositionLocalProvider(LocalHazeState provides hazeState) { + CompositionLocalProvider( + LocalHazeState provides if (ThemeConfig.enableBlur) hazeState else null + ) { when { ThemeResolver.isMiuixEngine(composeEngine) -> { val miuixFabPosition = when (floatingActionButtonPosition) { diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt index 86abfd33c..c548ce905 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -18,7 +17,11 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp 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.AnimatedTextLine +import io.legado.app.ui.widget.components.AppIcon +import top.yukonga.miuix.kmp.theme.MiuixTheme @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -28,8 +31,8 @@ fun TextCard( text: String, icon: ImageVector? = null, onClick: (() -> Unit)? = null, - backgroundColor: Color = MaterialTheme.colorScheme.primaryContainer, - contentColor: Color = MaterialTheme.colorScheme.onPrimaryContainer, + backgroundColor: Color? = null, + contentColor: Color? = null, cornerRadius: Dp = 8.dp, horizontalPadding: Dp = 8.dp, verticalPadding: Dp = 2.dp, @@ -37,11 +40,26 @@ fun TextCard( spacing: Dp = 4.dp, textStyle: TextStyle = LegadoTheme.typography.labelSmallEmphasized ) { + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + + val defaultBackground = if (isMiuix) + MiuixTheme.colorScheme.surfaceContainer + else + MaterialTheme.colorScheme.primaryContainer + + val defaultContent = if (isMiuix) + MiuixTheme.colorScheme.onSurface + else + MaterialTheme.colorScheme.primary + + val finalBackgroundColor = backgroundColor ?: defaultBackground + val finalContentColor = contentColor ?: defaultContent + NormalCard( modifier = modifier, shape = RoundedCornerShape(cornerRadius), - containerColor = backgroundColor, - contentColor = contentColor, + containerColor = finalBackgroundColor, + contentColor = finalContentColor, onClick = onClick ) { Row( @@ -53,10 +71,10 @@ fun TextCard( ) { if (icon != null) { - Icon( + AppIcon( imageVector = icon, contentDescription = null, - tint = contentColor, + tint = finalContentColor, modifier = Modifier.size(iconSize) ) Spacer(modifier = Modifier.width(spacing)) @@ -65,7 +83,7 @@ fun TextCard( AnimatedTextLine( text = text, style = textStyle, - color = contentColor + color = finalContentColor ) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt index 1d4048933..b88003858 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt @@ -5,7 +5,6 @@ import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.RowScope @@ -17,16 +16,12 @@ import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.lerp import androidx.compose.ui.graphics.vector.ImageVector import io.legado.app.ui.widget.components.AnimatedTextLine import io.legado.app.ui.widget.components.SearchBarSection @@ -58,19 +53,10 @@ fun DynamicTopAppBar( var showMenu by remember { mutableStateOf(false) } val isSelecting = state.selectedIds.isNotEmpty() - val containerColor = GlassTopAppBarDefaults.containerColor() - val scrolledColor = GlassTopAppBarDefaults.scrolledContainerColor() - - val animatedColor by remember(scrollBehavior, containerColor, scrolledColor) { - derivedStateOf { - lerp(containerColor, scrolledColor, scrollBehavior.collapsedFraction) - } - } GlassMediumFlexibleTopAppBar( modifier = Modifier - .fillMaxWidth() - .background(animatedColor), + .fillMaxWidth(), title = when { state.isLoading -> "请稍后..." isSelecting -> "已选择 ${state.selectedIds.size}/${state.items.size}" @@ -117,10 +103,6 @@ fun DynamicTopAppBar( } }, scrollBehavior = scrollBehavior, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.Transparent, - scrolledContainerColor = Color.Transparent - ), bottomContent = { AnimatedVisibility( visible = state.isSearch && !isSelecting, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt index e06f0d6da..0a1cee57e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.widget.components.topbar +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.RowScope @@ -13,6 +14,7 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.lerp import androidx.compose.ui.text.style.TextOverflow import io.legado.app.ui.config.themeConfig.ThemeConfig import io.legado.app.ui.theme.LegadoTheme @@ -35,28 +37,54 @@ fun GlassMediumFlexibleTopAppBar( scrollBehavior: GlassTopAppBarScrollBehavior? = null, navigationIcon: @Composable () -> Unit = {}, actions: @Composable RowScope.() -> Unit = {}, - colors: TopAppBarColors = GlassTopAppBarDefaults.glassColors(), bottomContent: @Composable (ColumnScope.() -> Unit)? = null ) { val hazeState = LocalHazeState.current + val composeEngine = LegadoTheme.composeEngine + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + + val containerColor = if (!isMiuix) { + GlassTopAppBarDefaults.containerColor() + } else { + GlassTopAppBarDefaults.getMiuixAppBarColor() + } + + val scrolledColor = if (!isMiuix) { + GlassTopAppBarDefaults.scrolledContainerColor() + } else { + GlassTopAppBarDefaults.getMiuixAppBarColor() + } + + val animatedColor = if (!isMiuix) { + val fraction = scrollBehavior?.collapsedFraction ?: 0f + lerp(containerColor, scrolledColor, fraction) + } else { + containerColor + } + val finalModifier = if (hazeState != null) { modifier.responsiveHazeEffect(state = hazeState) } else { - modifier + modifier.background(color = animatedColor) } - val composeEngine = LegadoTheme.composeEngine + val transparentColors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Transparent, + scrolledContainerColor = Color.Transparent + ) - Column(modifier = finalModifier) { + Column( + modifier = finalModifier + ) { when { - ThemeResolver.isMiuixEngine(composeEngine) -> { + isMiuix -> { MiuixTopAppBar( modifier = Modifier, title = title, navigationIcon = navigationIcon, actions = actions, - color = GlassTopAppBarDefaults.getMiuixAppBarColor(), + color = Color.Transparent, // 内部强制透明,透出 Column 背景 scrollBehavior = (scrollBehavior as? MiuixGlassScrollBehavior)?.miuixBehavior ) } @@ -77,7 +105,7 @@ fun GlassMediumFlexibleTopAppBar( navigationIcon = navigationIcon, actions = actions, scrollBehavior = (scrollBehavior as? M3GlassScrollBehavior)?.m3Behavior, - colors = colors + colors = transparentColors // 应用透明背景 ) } else { TopAppBar( @@ -93,11 +121,13 @@ fun GlassMediumFlexibleTopAppBar( navigationIcon = navigationIcon, actions = actions, scrollBehavior = (scrollBehavior as? M3GlassScrollBehavior)?.m3Behavior, - colors = colors + colors = transparentColors // 应用透明背景 ) } } } + + // 现在的 bottomContent 完美包裹在外层 Column 内,共享渐变和模糊效果! bottomContent?.invoke(this) } } diff --git a/app/src/main/res/values-zh-rCN/arrays.xml b/app/src/main/res/values-zh-rCN/arrays.xml index 69c46de9a..8192fd458 100644 --- a/app/src/main/res/values-zh-rCN/arrays.xml +++ b/app/src/main/res/values-zh-rCN/arrays.xml @@ -178,7 +178,6 @@ Material Design - SaltUI Miuix diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 68ad73fe8..a4f7ff643 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -493,7 +493,7 @@ 分享选中源 扫描二维码 选中时点击可弹出菜单 - 主题 + 主题模式 深色模式 选择主题模式 加入 QQ 群 diff --git a/app/src/main/res/values/array_values.xml b/app/src/main/res/values/array_values.xml index 01970a0b9..ba25c9a82 100644 --- a/app/src/main/res/values/array_values.xml +++ b/app/src/main/res/values/array_values.xml @@ -105,7 +105,6 @@ material - salt miuix diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index a4a405595..e491b130b 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -219,7 +219,6 @@ Material Design - SaltUI Miuix diff --git a/app/version.properties b/app/version.properties index 910d3613b..270eb3383 100644 --- a/app/version.properties +++ b/app/version.properties @@ -1,5 +1,5 @@ VERSION_MAJOR=3 VERSION_MINOR=26 -VERSION_PATCH=10 +VERSION_PATCH=11 VERSION_SUFFIX=1 # 1 = Pre, 0 = Release \ No newline at end of file From dd88417f8afb0ac26c12f6f20c9a7c31e76b88aa Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Fri, 3 Apr 2026 01:08:51 +0800 Subject: [PATCH 3/3] =?UTF-8?q?[=E4=BC=98=E5=8C=96]=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=8E=A7=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/ui/about/AboutScreen.kt | 3 - .../io/legado/app/ui/about/AppLogSheet.kt | 6 +- .../app/ui/book/bookmark/AllBookmarkScreen.kt | 38 ++- .../app/ui/book/explore/ExploreShowScreen.kt | 183 ++++++------ .../app/ui/book/group/GroupEditSheet.kt | 17 +- .../ui/book/import/remote/RemoteBookScreen.kt | 75 +++-- .../ui/book/readRecord/ReadRecordScreen.kt | 110 ++++--- .../book/searchContent/SearchContentScreen.kt | 2 +- .../io/legado/app/ui/book/toc/TocScreen.kt | 51 ++-- .../app/ui/book/toc/rule/TxtRuleScreen.kt | 173 ++++++----- .../config/backupConfig/BackupConfigScreen.kt | 43 ++- .../config/coverConfig/CoverConfigScreen.kt | 21 +- .../ui/config/coverConfig/CoverManageSheet.kt | 25 +- .../coverConfig/CoverRuleConfigSheet.kt | 6 +- .../otherConfig/CheckSourceBottomSheet.kt | 8 +- .../DirectLinkUploadBottomSheet.kt | 6 +- .../config/otherConfig/OtherConfigScreen.kt | 43 ++- .../app/ui/config/readConfig/PageKeySheet.kt | 5 +- .../ui/config/readConfig/ReadConfigScreen.kt | 7 +- .../themeConfig/BackgroundImageManageSheet.kt | 25 +- .../themeConfig/LauncherIconPickerSheet.kt | 6 +- .../app/ui/config/themeConfig/ThemeConfig.kt | 4 +- .../config/themeConfig/ThemeConfigScreen.kt | 100 ++++--- .../ui/config/themeConfig/ThemeListDialog.kt | 6 +- .../app/ui/dict/rule/DictRuleEditSheet.kt | 5 +- .../legado/app/ui/dict/rule/DictRuleScreen.kt | 171 +++++------ .../java/io/legado/app/ui/main/MainScreen.kt | 5 +- .../ui/main/bookshelf/BookshelfConfigSheet.kt | 23 +- .../app/ui/main/bookshelf/BookshelfScreen.kt | 111 ++++--- .../app/ui/main/bookshelf/GroupManageSheet.kt | 97 +++--- .../app/ui/main/explore/ExploreScreen.kt | 22 +- .../java/io/legado/app/ui/main/my/MyScreen.kt | 2 +- .../io/legado/app/ui/main/rss/RssScreen.kt | 22 +- .../app/ui/replace/ReplaceRuleScreen.kt | 138 ++++----- .../ui/rss/favorites/RssFavoritesScreen.kt | 27 +- .../ui/rss/source/manage/RssSourceScreen.kt | 100 +++---- .../app/ui/rss/subscription/RuleSubScreen.kt | 5 +- .../java/io/legado/app/ui/theme/AppTheme.kt | 257 ++++++++++++++-- .../io/legado/app/ui/theme/LegadoTheme.kt | 109 ++++++- .../io/legado/app/ui/theme/ThemeManager.kt | 5 +- .../io/legado/app/ui/theme/ThemeResolver.kt | 8 + .../legado/app/ui/widget/CollapsibleHeader.kt | 28 +- .../app/ui/widget/components/AppIcon.kt | 49 ---- .../ui/widget/components/AppNavigationBar.kt | 4 +- .../app/ui/widget/components/AppTextField.kt | 127 ++++++++ .../ui/widget/components/EmptyMessageView.kt | 1 + .../components/GroupManageBottomSheet.kt | 39 +-- .../ui/widget/components/SearchBarSection.kt | 130 ++------ .../app/ui/widget/components/ValueStepper.kt | 52 ++++ .../components/bookmark/BookmarkEditSheet.kt | 41 +-- .../components/bookmark/BookmarkItem.kt | 9 +- .../ui/widget/components/button/AppButton.kt | 74 +++++ .../widget/components/button/AppIconButton.kt | 61 ++++ .../{MiuixBackButton.kt => MiuixButton.kt} | 8 +- .../components/button/SmallIconButton.kt | 134 ++++++--- .../components/button/SmallTextButton.kt | 49 +++- .../widget/components/button/TopBarButton.kt | 7 +- .../components/card/SelectionItemCard.kt | 1 - .../app/ui/widget/components/card/TextCard.kt | 21 +- .../widget/components/cover/BookshelfCover.kt | 16 - .../components/dialog/ColorPickerSheet.kt | 5 +- .../widget/components/divider/PillDivider.kt | 36 ++- .../components/divider/PillHeaderDivider.kt | 5 +- .../components/filePicker/FilePickerSheet.kt | 27 +- .../app/ui/widget/components/icon/AppIcon.kt | 88 ++++++ .../app/ui/widget/components/icon/AppIcons.kt | 54 ++++ .../importComponents/ImportComponents.kt | 181 +++++------- .../lazylist/VerticalFastScroller.kt | 3 +- .../components/menuItem/RoundDropdownMenu.kt | 60 ++-- .../menuItem/RoundDropdownMenuItem.kt | 113 +++++-- .../modalBottomSheet/AppModalBottomSheet.kt | 138 +++++++++ .../modalBottomSheet/GlassModalBottomSheet.kt | 64 ---- .../widget/components/rules/RuleEditSheet.kt | 6 +- .../settingItem/CompactSettingItems.kt | 277 +++++++++++------- .../components/settingItem/ListSettingItem.kt | 3 +- .../settingItem/SwitchSettingItem.kt | 19 +- .../{AdaptiveTabRow.kt => AppTabRow.kt} | 6 +- .../components/{ => text}/AnimatedText.kt | 3 +- .../app/ui/widget/components/text/AppText.kt | 149 ++++------ .../components/topbar/DynamicTopAppBar.kt | 9 +- .../topbar/GlassMediumFlexibleTopAppBar.kt | 2 +- 81 files changed, 2461 insertions(+), 1708 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/button/AppButton.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/button/AppIconButton.kt rename app/src/main/java/io/legado/app/ui/widget/components/button/{MiuixBackButton.kt => MiuixButton.kt} (92%) create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt delete mode 100644 app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/GlassModalBottomSheet.kt rename app/src/main/java/io/legado/app/ui/widget/components/tabRow/{AdaptiveTabRow.kt => AppTabRow.kt} (95%) rename app/src/main/java/io/legado/app/ui/widget/components/{ => text}/AnimatedText.kt (98%) diff --git a/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt b/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt index 59f0f1bb7..d1bc57845 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt @@ -15,7 +15,6 @@ 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.colorScheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -91,8 +90,6 @@ fun AboutScreen( .wrapContentWidth(Alignment.CenterHorizontally)) TextCard( text = versionName, - backgroundColor = colorScheme.tertiaryContainer, - contentColor = colorScheme.onTertiaryContainer, cornerRadius = 8.dp, modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt b/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt index ba3706e15..54bff48eb 100644 --- a/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt +++ b/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt @@ -31,7 +31,7 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.LogUtils import java.util.Date @@ -39,12 +39,14 @@ import java.util.Date @OptIn(ExperimentalMaterial3Api::class) @Composable fun AppLogSheet( + show: Boolean, onDismissRequest: () -> Unit ) { var logs by remember { mutableStateOf(AppLog.logs) } var showStackTrace by remember { mutableStateOf(null) } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Row( diff --git a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt b/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt index 025d24f01..496916e53 100644 --- a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt @@ -48,7 +48,6 @@ 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 @@ -128,7 +127,7 @@ fun AllBookmarkScreen( onDismissRequest = { showMenu = false } ) { RoundDropdownMenuItem( - text = { AppText("导出 JSON") }, + text = "导出 JSON", onClick = { showMenu = false pendingExportIsMd = false @@ -136,7 +135,7 @@ fun AllBookmarkScreen( } ) RoundDropdownMenuItem( - text = { AppText("导出 Markdown") }, + text = "导出 Markdown", onClick = { showMenu = false pendingExportIsMd = true @@ -238,22 +237,21 @@ fun AllBookmarkScreen( } } - if (showBottomSheet && editingBookmark != null) { - BookmarkEditSheet( - bookmark = editingBookmark!!, - onDismiss = { - showBottomSheet = false - editingBookmark = null - }, - onSave = { updatedBookmark -> - viewModel.updateBookmark(updatedBookmark) - showBottomSheet = false - }, - onDelete = { bookmarkToDelete -> - viewModel.deleteBookmark(bookmarkToDelete) - showBottomSheet = false - } - ) - } + BookmarkEditSheet( + show = showBottomSheet && editingBookmark != null, + bookmark = editingBookmark ?: Bookmark(), + onDismiss = { + showBottomSheet = false + editingBookmark = null + }, + onSave = { updatedBookmark -> + viewModel.updateBookmark(updatedBookmark) + showBottomSheet = false + }, + onDelete = { bookmarkToDelete -> + viewModel.deleteBookmark(bookmarkToDelete) + showBottomSheet = false + } + ) } } diff --git a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt index 3f494c6f4..8700c3211 100644 --- a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt @@ -90,7 +90,7 @@ import io.legado.app.ui.widget.components.card.TextCard 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.modalBottomSheet.AppModalBottomSheet 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 @@ -180,112 +180,111 @@ fun ExploreShowScreen( } } - if (showGridCountSheet) { - GlassModalBottomSheet( + AppModalBottomSheet( + show = showGridCountSheet, + modifier = Modifier + .padding(16.dp), + onDismissRequest = { showGridCountSheet = false } + ) { + Row( modifier = Modifier - .padding(16.dp), - onDismissRequest = { showGridCountSheet = false } + .fillMaxWidth() + .padding(bottom = 16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 16.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - AppText( - text = "布局列数", - style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold) - ) - - Spacer(modifier = Modifier.width(12.dp)) - - TextCard( - text = "$gridColumnCount 列", - textStyle = LegadoTheme.typography.titleSmall, - verticalPadding = 4.dp, - horizontalPadding = 12.dp, - cornerRadius = 12.dp - ) - } - - Slider( - value = gridColumnCount.toFloat(), - onValueChange = { - val col = it.toInt().coerceIn(1, 10) - viewModel.saveGridCount(col) - }, - valueRange = 1f..10f, - steps = 8, - modifier = Modifier.padding(horizontal = 20.dp) + AppText( + text = "布局列数", + style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold) ) - Spacer(Modifier.height(24.dp)) + Spacer(modifier = Modifier.width(12.dp)) - OutlinedButton( - onClick = { showGridCountSheet = false }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - ) { - AppText("完成") - } + TextCard( + text = "$gridColumnCount 列", + textStyle = LegadoTheme.typography.titleSmall, + verticalPadding = 4.dp, + horizontalPadding = 12.dp, + cornerRadius = 12.dp + ) + } + + Slider( + value = gridColumnCount.toFloat(), + onValueChange = { + val col = it.toInt().coerceIn(1, 10) + viewModel.saveGridCount(col) + }, + valueRange = 1f..10f, + steps = 8, + modifier = Modifier.padding(horizontal = 20.dp) + ) + + Spacer(Modifier.height(24.dp)) + + OutlinedButton( + onClick = { showGridCountSheet = false }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + AppText("完成") } } - if (showKindSheet) { - GlassModalBottomSheet( - onDismissRequest = { showKindSheet = false } - ) { - var kindQuery by remember { mutableStateOf("") } + AppModalBottomSheet( + show = showKindSheet, + onDismissRequest = { showKindSheet = false } + ) { - SearchBarSection( - query = kindQuery, - backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh, - onQueryChange = { kindQuery = it }, - placeholder = "选择或搜索分类", - ) + var kindQuery by remember { mutableStateOf("") } - val filteredKinds = remember(kindQuery, kinds) { - if (kindQuery.isBlank()) kinds - else kinds.filter { kind -> - kind.title.contains(kindQuery, ignoreCase = true) || - (kind.url?.contains(kindQuery, ignoreCase = true) == true) - } + SearchBarSection( + query = kindQuery, + backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh, + onQueryChange = { kindQuery = it }, + placeholder = "选择或搜索分类", + ) + + val filteredKinds = remember(kindQuery, kinds) { + if (kindQuery.isBlank()) kinds + else kinds.filter { kind -> + kind.title.contains(kindQuery, ignoreCase = true) || + (kind.url?.contains(kindQuery, ignoreCase = true) == true) } + } - LazyVerticalGrid( - columns = GridCells.Fixed(3), - contentPadding = PaddingValues(16.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier.weight(1f, fill = false) - ) { - itemsIndexed( - items = filteredKinds, - key = { index, kind -> "${kind.url ?: kind.title}_$index" }, - span = { _, kind -> - val isClickable = !kind.url.isNullOrBlank() - if (isClickable) GridItemSpan(1) else GridItemSpan(3) + LazyVerticalGrid( + columns = GridCells.Fixed(3), + contentPadding = PaddingValues(16.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.weight(1f, fill = false) + ) { + itemsIndexed( + items = filteredKinds, + key = { index, kind -> "${kind.url ?: kind.title}_$index" }, + span = { _, kind -> + val isClickable = !kind.url.isNullOrBlank() + if (isClickable) GridItemSpan(1) else GridItemSpan(3) + } + ) { _, kind -> + KindGridItem( + modifier = Modifier.animateItem(), + kind = kind, + currentTitle = selectedTitle ?: title, + onClick = { + showKindSheet = false + viewModel.switchExploreUrl(kind) } - ) { _, kind -> - KindGridItem( - modifier = Modifier.animateItem(), - kind = kind, - currentTitle = selectedTitle ?: title, - onClick = { - showKindSheet = false - viewModel.switchExploreUrl(kind) - } - ) - } + ) } - } } + AppScaffold( modifier = Modifier .nestedScroll(scrollBehavior.nestedScrollConnection), @@ -339,7 +338,7 @@ fun ExploreShowScreen( onDismissRequest = { showMenu = false } ) { RoundDropdownMenuItem( - text = { AppText("全部显示") }, + text = "全部显示", onClick = { viewModel.setFilterState(BookFilterState.SHOW_ALL) showMenu = false @@ -351,7 +350,7 @@ fun ExploreShowScreen( ) RoundDropdownMenuItem( - text = { AppText("隐藏已在书架的同源书籍") }, + text = "隐藏已在书架的同源书籍", onClick = { viewModel.setFilterState(BookFilterState.HIDE_IN_SHELF) showMenu = false @@ -363,7 +362,7 @@ fun ExploreShowScreen( ) RoundDropdownMenuItem( - text = { AppText("隐藏已在书架的非同源书籍") }, + text = "隐藏已在书架的非同源书籍", onClick = { viewModel.setFilterState(BookFilterState.HIDE_SAME_NAME_AUTHOR) showMenu = false @@ -375,7 +374,7 @@ fun ExploreShowScreen( ) RoundDropdownMenuItem( - text = { AppText("只显示不在书架的书籍") }, + text = "只显示不在书架的书籍", onClick = { viewModel.setFilterState(BookFilterState.SHOW_NOT_IN_SHELF_ONLY) showMenu = false diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt index 472ce06ee..f10bfccab 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -36,9 +35,8 @@ 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.modalBottomSheet.AppModalBottomSheet 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 @@ -55,11 +53,12 @@ import java.io.FileOutputStream @OptIn(ExperimentalMaterial3Api::class) @Composable fun GroupEditSheet( + show: Boolean, group: BookGroup? = null, onDismissRequest: () -> Unit, viewModel: GroupViewModel = koinViewModel() ) { - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet(show = show, onDismissRequest = onDismissRequest) { GroupEditContent( group = group, onDismissRequest = onDismissRequest, @@ -108,17 +107,9 @@ fun GroupEditContent( Column( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(bottom = 16.dp) .verticalScroll(rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, ) { - AppText( - text = stringResource(R.string.group_edit), - style = LegadoTheme.typography.titleLarge, - modifier = Modifier.padding(vertical = 16.dp) - ) - Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.Top, diff --git a/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt b/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt index 3f0588aee..6a34fa1a3 100644 --- a/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt @@ -88,7 +88,7 @@ import io.legado.app.ui.widget.components.button.SmallTonalIconButton 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.ArchiveUtils import io.legado.app.utils.ConvertUtils @@ -199,42 +199,41 @@ fun RemoteBookScreen( } } - if (showSheet != null) { - GlassModalBottomSheet( - onDismissRequest = { showSheet = null } - ) { - when (val state = showSheet) { - is RemoteBookSheet.Servers -> { - ServersSheetContent( - servers = uiState.servers, - selectedServerId = uiState.selectedServerId, - onSelect = { - viewModel.selectServer(it) - showSheet = null - }, - onEdit = { showSheet = RemoteBookSheet.ServerConfig(it) }, - onDelete = { viewModel.deleteServer(it) }, - onAdd = { showSheet = RemoteBookSheet.ServerConfig(null) }, - onDefault = { - viewModel.selectServer(AppConst.DEFAULT_WEBDAV_ID) - showSheet = null - } - ) - } - - is RemoteBookSheet.ServerConfig -> { - ServerConfigSheetContent( - server = state.server, - onSave = { - viewModel.saveServer(it) - showSheet = RemoteBookSheet.Servers - }, - onCancel = { showSheet = RemoteBookSheet.Servers } - ) - } - - else -> {} + AppModalBottomSheet( + show = showSheet != null, + onDismissRequest = { showSheet = null } + ) { + when (val state = showSheet) { + is RemoteBookSheet.Servers -> { + ServersSheetContent( + servers = uiState.servers, + selectedServerId = uiState.selectedServerId, + onSelect = { + viewModel.selectServer(it) + showSheet = null + }, + onEdit = { showSheet = RemoteBookSheet.ServerConfig(it) }, + onDelete = { viewModel.deleteServer(it) }, + onAdd = { showSheet = RemoteBookSheet.ServerConfig(null) }, + onDefault = { + viewModel.selectServer(AppConst.DEFAULT_WEBDAV_ID) + showSheet = null + } + ) } + + is RemoteBookSheet.ServerConfig -> { + ServerConfigSheetContent( + server = state.server, + onSave = { + viewModel.saveServer(it) + showSheet = RemoteBookSheet.Servers + }, + onCancel = { showSheet = RemoteBookSheet.Servers } + ) + } + + else -> {} } } @@ -260,7 +259,7 @@ fun RemoteBookScreen( }, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText("按名称排序") }, + text = "按名称排序", onClick = { viewModel.toggleSort(RemoteBookSort.Name) dismiss() @@ -272,7 +271,7 @@ fun RemoteBookScreen( } ) RoundDropdownMenuItem( - text = { AppText("按时间排序") }, + text = "按时间排序", onClick = { viewModel.toggleSort(RemoteBookSort.Default) dismiss() diff --git a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt b/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt index 3263ec78d..56314ad97 100644 --- a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt @@ -32,13 +32,9 @@ import androidx.compose.material.icons.filled.Schedule import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Timeline import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -78,13 +74,14 @@ 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.CollapsibleHeader import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.EmptyMessageView 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 +import io.legado.app.ui.widget.components.button.AppIconButton import io.legado.app.ui.widget.components.button.TopbarNavigationButton +import io.legado.app.ui.widget.components.card.GlassCard import io.legado.app.ui.widget.components.cover.Cover import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarTopBar import io.legado.app.ui.widget.components.heatmap.HeatmapConfig @@ -96,9 +93,11 @@ import io.legado.app.ui.widget.components.heatmap.WeekdayLabelsColumn import io.legado.app.ui.widget.components.heatmap.rememberDateRange import io.legado.app.ui.widget.components.heatmap.rememberDaysInRange 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.icon.AppIcon +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet 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.AnimatedTextLine import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults @@ -164,7 +163,7 @@ fun ReadRecordScreen( TopbarNavigationButton(onClick = onBackClick) }, actions = { - IconButton(onClick = { + AppIconButton(onClick = { val newMode = when (displayMode) { DisplayMode.AGGREGATE -> DisplayMode.TIMELINE DisplayMode.TIMELINE -> DisplayMode.LATEST @@ -178,13 +177,16 @@ fun ReadRecordScreen( DisplayMode.LATEST -> Icons.AutoMirrored.Filled.List } val description = if (displayMode == DisplayMode.AGGREGATE) "Switch to Timeline" else "Switch to Aggregate" - Icon(icon, description) + AppIcon(icon, description) } - IconButton(onClick = { showCalendar = !showCalendar }) { - Icon(Icons.Default.CalendarMonth, contentDescription = "Toggle Calendar") + AppIconButton(onClick = { showCalendar = !showCalendar }) { + AppIcon( + Icons.Default.CalendarMonth, + contentDescription = "Toggle Calendar" + ) } - IconButton(onClick = { showSearch = !showSearch }) { - Icon(Icons.Default.Search, contentDescription = null) + AppIconButton(onClick = { showSearch = !showSearch }) { + AppIcon(Icons.Default.Search, contentDescription = null) } }, scrollBehavior = scrollBehavior @@ -314,24 +316,23 @@ fun ReadRecordScreen( ) } - if (showCalendar) { - GlassModalBottomSheet( - onDismissRequest = { showCalendar = false } - ) { - HeatmapCalendarSection( - dailyReadCounts = state.dailyReadCounts, - dailyReadTimes = state.dailyReadTimes, - selectedDate = state.selectedDate, - onDateSelected = { date -> - viewModel.setSelectedDate(date) - showCalendar = false - }, - onClearDate = { - viewModel.setSelectedDate(null) - showCalendar = false - } - ) - } + AppModalBottomSheet( + show = showCalendar, + onDismissRequest = { showCalendar = false } + ) { + HeatmapCalendarSection( + dailyReadCounts = state.dailyReadCounts, + dailyReadTimes = state.dailyReadTimes, + selectedDate = state.selectedDate, + onDateSelected = { date -> + viewModel.setSelectedDate(date) + showCalendar = false + }, + onClearDate = { + viewModel.setSelectedDate(null) + showCalendar = false + } + ) } @@ -869,28 +870,27 @@ fun DateHeader( date: String, dailyTotalTime: Long? = null ) { - val dateText = formatFriendlyDate(date) - SectionHeader( + CollapsibleHeader( + showIcon = false, + isCollapsed = false, + onToggle = { }, + title = "", titleContent = { - Column { + val dateText = formatFriendlyDate(date) + AppText( + text = dateText, + style = LegadoTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + color = LegadoTheme.colorScheme.primary + ) + dailyTotalTime?.let { total -> AppText( - text = dateText, - style = LegadoTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.secondary + text = "已读 ${formatDuring(total)}", + style = LegadoTheme.typography.bodySmall, + color = LegadoTheme.colorScheme.onSurface ) - - dailyTotalTime?.let { total -> - AppText( - text = "已读 ${formatDuring(total)}", - style = LegadoTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurface - ) - } } - }, - detailContent = null, - horizontalArrangement = Arrangement.Start + } ) } @@ -912,14 +912,12 @@ fun ReadingSummaryCard( val totalDurationMinutes = totalTimeMillis / 60000 - Card( + GlassCard( onClick = onClick, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surfaceContainer - ) + containerColor = LegadoTheme.colorScheme.surfaceContainer ) { Row( modifier = Modifier @@ -934,7 +932,7 @@ fun ReadingSummaryCard( AppText( text = title, style = LegadoTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.primary + color = LegadoTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(4.dp)) @@ -947,7 +945,7 @@ fun ReadingSummaryCard( AppText( text = "$bookCount", style = LegadoTheme.typography.headlineMedium, - color = MaterialTheme.colorScheme.primary, + color = LegadoTheme.colorScheme.primary, fontWeight = FontWeight.Bold, ) AppText( @@ -965,7 +963,7 @@ fun ReadingSummaryCard( AppText( text = "共阅读 $timeString", style = LegadoTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant + color = LegadoTheme.colorScheme.onSurfaceVariant ) } diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt index 813129e82..ff6d87a8c 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt @@ -310,7 +310,7 @@ fun SearchHistoryList( AppText( text = "搜索历史", style = LegadoTheme.typography.titleSmallEmphasized, - color = MaterialTheme.colorScheme.primary, + color = LegadoTheme.colorScheme.primary, modifier = Modifier.align(Alignment.Center) ) SmallAnimatedActionButton( diff --git a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt index b1ede3b7d..a737a4e70 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt @@ -313,33 +313,33 @@ fun TocScreen( when (pagerState.currentPage) { 0 -> { RoundDropdownMenuItem( - text = { AppText("使用替换规则") }, + text = "使用替换规则", trailingIcon = { Checkbox(checked = useReplace, onCheckedChange = null) }, onClick = { viewModel.toggleUseReplace() } ) RoundDropdownMenuItem( - text = { AppText("显示字数") }, + text = "显示字数", trailingIcon = { Checkbox(checked = showWordCount, onCheckedChange = null) }, onClick = { viewModel.toggleShowWordCount() } ) RoundDropdownMenuItem( - text = { AppText("反转目录") }, + text = "反转目录", onClick = { viewModel.reverseToc() } ) PillDivider() RoundDropdownMenuItem( - text = { AppText("替换规则") }, + text = "替换规则", onClick = { onOpenReplaceRule(null) dismiss() } ) RoundDropdownMenuItem( - text = { AppText("新建替换规则") }, + text = "新建替换规则", onClick = { val scopes = mutableListOf() book?.name?.let { scopes.add(it) } @@ -359,7 +359,7 @@ fun TocScreen( if (book?.isLocal == true) { PillHeaderDivider(title = "本地书籍选项") RoundDropdownMenuItem( - text = { AppText("本地书籍目录规则") }, + text = "本地书籍目录规则", onClick = { val intent = Intent(context, TxtTocRuleActivity::class.java).apply { @@ -370,7 +370,7 @@ fun TocScreen( } ) RoundDropdownMenuItem( - text = { AppText("拆分超长章节") }, + text = "拆分超长章节", trailingIcon = { Checkbox( checked = viewModel.isSplitLongChapter, @@ -387,7 +387,7 @@ fun TocScreen( else -> { RoundDropdownMenuItem( - text = { AppText("导出书签为JSON") }, + text = "导出书签为JSON", onClick = { val dateFormat = SimpleDateFormat( "yyyyMMdd_HHmm", @@ -399,7 +399,7 @@ fun TocScreen( } ) RoundDropdownMenuItem( - text = { AppText("导出书签为MarkDown") }, + text = "导出书签为MarkDown", onClick = { val dateFormat = SimpleDateFormat( "yyyyMMdd_HHmm", @@ -465,13 +465,13 @@ fun TocScreen( onDismissRequest = { showVolumeMenu = false } ) { RoundDropdownMenuItem( - text = { AppText("展开所有卷") }, + text = "展开所有卷", onClick = { viewModel.expandAllVolumes(); showVolumeMenu = false } ) RoundDropdownMenuItem( - text = { AppText("收起所有卷") }, + text = "收起所有卷", onClick = { viewModel.collapseAllVolumes(); showVolumeMenu = false } @@ -483,7 +483,7 @@ fun TocScreen( PillHeaderDivider(title = "快速跳转") volumeItems.forEach { uiItem -> RoundDropdownMenuItem( - text = { AppText(uiItem.title) }, + text = uiItem.title, onClick = { scope.launch { val targetIndex = @@ -594,20 +594,19 @@ fun TocScreen( } } - if (editingBookmark != null) { - BookmarkEditSheet( - bookmark = editingBookmark!!, - onDismiss = { editingBookmark = null }, - onSave = { updatedBookmark -> - viewModel.updateBookmark(updatedBookmark) - editingBookmark = null - }, - onDelete = { bookmarkToDelete -> - viewModel.deleteBookmark(bookmarkToDelete) - editingBookmark = null - } - ) - } + BookmarkEditSheet( + show = editingBookmark != null, + bookmark = editingBookmark!!, + onDismiss = { editingBookmark = null }, + onSave = { updatedBookmark -> + viewModel.updateBookmark(updatedBookmark) + editingBookmark = null + }, + onDelete = { bookmarkToDelete -> + viewModel.deleteBookmark(bookmarkToDelete) + editingBookmark = null + } + ) } } diff --git a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt index dd17674c4..02d004f74 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt @@ -5,7 +5,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -44,13 +43,11 @@ 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 import io.legado.app.ui.widget.components.card.ReorderableSelectionItem import io.legado.app.ui.widget.components.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.importComponents.BaseImportUiState import io.legado.app.ui.widget.components.importComponents.BatchImportDialog import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn @@ -154,54 +151,49 @@ fun TxtRuleScreen( ) } - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - title = stringResource(R.string.export), - onSelectSysDir = { - showExportSheet = false - exportDoc.launch("exportDictRule.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + title = stringResource(R.string.export), + onSelectSysDir = { + showExportSheet = false + exportDoc.launch("exportDictRule.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_txt_toc_rule), - onSelectSysFile = { types -> - importDoc.launch(types) - showImportSheet = false - }, - onManualInput = { - showUrlInput = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = "导入词典规则", - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - itemContent = { rule, _ -> - Column { - AppText(rule.name, style = LegadoTheme.typography.titleMedium) - AppText(rule.rule, style = LegadoTheme.typography.bodySmall, maxLines = 1) - } - } - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_txt_toc_rule), + onSelectSysFile = { types -> + importDoc.launch(types) + showImportSheet = false + }, + onManualInput = { + showUrlInput = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) + + BatchImportDialog( + title = "导入词典规则", + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + itemTitle = { rule -> rule.name }, + itemSubtitle = { rule -> + rule.rule.takeIf { it.isNotBlank() } + } + ) LaunchedEffect(reorderableState.isAnyItemDragging) { if (!reorderableState.isAnyItemDragging) { @@ -229,48 +221,47 @@ fun TxtRuleScreen( ) } - if (showEditSheet) { - RuleEditSheet( - rule = editingRule, - title = stringResource(R.string.txt_toc_rule), - label1 = stringResource(R.string.regex), - label2 = stringResource(R.string.example), - onDismissRequest = { - showEditSheet = false - editingRule = null - }, - onSave = { updatedRule -> - //TODO:我很想把他改为自增主键,但为了兼容性日后再说 - if (editingRule == null) { - viewModel.insert(updatedRule) - } else { - viewModel.update(updatedRule) - } - showEditSheet = false - editingRule = null - }, - onCopy = { viewModel.copyRule(it) }, - onPaste = { viewModel.pasteRule() }, - toFields = { r -> - RuleEditFields( - name = r?.name ?: "", - rule1 = r?.rule ?: "", - rule2 = r?.example ?: "" - ) - }, - fromFields = { fields, old -> - old?.copy( - name = fields.name, - rule = fields.rule1, - example = fields.rule2 - ) ?: TxtTocRule( - name = fields.name, - rule = fields.rule1, - example = fields.rule2 - ) + RuleEditSheet( + show = showEditSheet, + rule = editingRule, + title = stringResource(R.string.txt_toc_rule), + label1 = stringResource(R.string.regex), + label2 = stringResource(R.string.example), + onDismissRequest = { + showEditSheet = false + editingRule = null + }, + onSave = { updatedRule -> + //TODO:我很想把他改为自增主键,但为了兼容性日后再说 + if (editingRule == null) { + viewModel.insert(updatedRule) + } else { + viewModel.update(updatedRule) } - ) - } + showEditSheet = false + editingRule = null + }, + onCopy = { viewModel.copyRule(it) }, + onPaste = { viewModel.pasteRule() }, + toFields = { r -> + RuleEditFields( + name = r?.name ?: "", + rule1 = r?.rule ?: "", + rule2 = r?.example ?: "" + ) + }, + fromFields = { fields, old -> + old?.copy( + name = fields.name, + rule = fields.rule1, + example = fields.rule2 + ) ?: TxtTocRule( + name = fields.name, + rule = fields.rule1, + example = fields.rule2 + ) + } + ) RuleListScaffold( title = if (isPickMode) "选择目录规则" else "目录规则", @@ -312,7 +303,7 @@ fun TxtRuleScreen( snackbarHostState = snackbarHostState, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_str)) }, + text = stringResource(R.string.import_str), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) diff --git a/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt index e261c97d0..7bd26ad3b 100644 --- a/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt @@ -453,31 +453,30 @@ fun BackupConfigScreen( ) } - if (showBackupFilePicker) { - FilePickerSheet( - onDismissRequest = { showBackupFilePicker = false }, - onSelectSysDir = { - showBackupFilePicker = false - try { - selectBackupPathLauncher.launch(null) - } catch (e: Exception) { - } + FilePickerSheet( + show = showBackupFilePicker, + onDismissRequest = { showBackupFilePicker = false }, + onSelectSysDir = { + showBackupFilePicker = false + try { + selectBackupPathLauncher.launch(null) + } catch (e: Exception) { } - ) - } + } + ) - if (showRestoreFilePicker) { - FilePickerSheet( - onDismissRequest = { showRestoreFilePicker = false }, - onSelectSysDir = { - showRestoreFilePicker = false - try { - backupAndSelectLauncher.launch(null) - } catch (e: Exception) { - } + + FilePickerSheet( + show = showRestoreFilePicker, + onDismissRequest = { showRestoreFilePicker = false }, + onSelectSysDir = { + showRestoreFilePicker = false + try { + backupAndSelectLauncher.launch(null) + } catch (e: Exception) { } - ) - } + } + ) if (showRestoreSheet && backupNames.isNotEmpty()) { AlertDialog( diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt index 829901a72..e34790879 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt @@ -246,17 +246,17 @@ fun CoverConfigScreen( } } - if (showCoverRuleSheet) { - CoverRuleConfigSheet(onDismissRequest = { showCoverRuleSheet = false }) - } + CoverRuleConfigSheet( + show = showCoverRuleSheet, + onDismissRequest = { showCoverRuleSheet = false } + ) - manageKey?.let { key -> - CoverManageSheet( - preferenceKey = key, - onDismissRequest = { manageKey = null }, - viewModel = viewModel - ) - } + CoverManageSheet( + show = manageKey != null, + preferenceKey = manageKey!!, + onDismissRequest = { manageKey = null }, + viewModel = viewModel + ) showColorPickerByField?.let { field -> val initialColor = when (field) { @@ -268,6 +268,7 @@ fun CoverConfigScreen( } ColorPickerSheet( + show = showColorPickerByField != null, initialColor = initialColor, onDismissRequest = { showColorPickerByField = null }, onColorSelected = { color -> diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt index 7f28526ad..6fc5536d0 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt @@ -37,12 +37,13 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun CoverManageSheet( + show: Boolean, preferenceKey: String, onDismissRequest: () -> Unit, viewModel: CoverConfigViewModel @@ -62,7 +63,8 @@ fun CoverManageSheet( } val coverList = currentCovers.split(",").filter { it.isNotBlank() } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( @@ -142,14 +144,13 @@ fun CoverManageSheet( } } - if (showFilePicker) { - FilePickerSheet( - onDismissRequest = { showFilePicker = false }, - onSelectSysFiles = { - selectImages.launch("image/*") - showFilePicker = false - }, - allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") - ) - } + FilePickerSheet( + show = showFilePicker, + onDismissRequest = { showFilePicker = false }, + onSelectSysFiles = { + selectImages.launch("image/*") + showFilePicker = false + }, + allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") + ) } diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt index 56b5ceb74..0833f6f07 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt @@ -25,7 +25,7 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.InputSettingItem import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.toastOnUi @@ -36,6 +36,7 @@ import splitties.init.appCtx @OptIn(ExperimentalMaterial3Api::class) @Composable fun CoverRuleConfigSheet( + show: Boolean, onDismissRequest: () -> Unit ) { var enable by remember { mutableStateOf(false) } @@ -51,7 +52,8 @@ fun CoverRuleConfigSheet( coverRule = rule.coverRule } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt index 6be30bb24..e01b733c5 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import io.legado.app.ui.widget.components.text.AppText import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -21,19 +20,22 @@ 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 +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.SliderSettingItem +import io.legado.app.ui.widget.components.text.AppText import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun CheckSourceBottomSheet( + show: Boolean, viewModel: OtherConfigViewModel = koinViewModel(), onDismiss: () -> Unit ) { val context = LocalContext.current - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismiss ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt index ac5fdd38c..075cb3a89 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt @@ -42,7 +42,7 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject @@ -53,6 +53,7 @@ import io.legado.app.utils.toastOnUi @OptIn(ExperimentalMaterial3Api::class) @Composable fun DirectLinkUploadBottomSheet( + show: Boolean, viewModel: OtherConfigViewModel, onDismiss: () -> Unit ) { @@ -64,7 +65,8 @@ fun DirectLinkUploadBottomSheet( viewModel.initDirectLinkRule() } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismiss ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt index a86a882fa..413de582f 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt @@ -398,33 +398,30 @@ fun OtherConfigScreen( } } - if (showFilePicker) { - FilePickerSheet( - onDismissRequest = { showFilePicker = false }, - onSelectSysDir = { - showFilePicker = false - try { - selectDocTree.launch(null) - } catch (e: Exception) { + FilePickerSheet( + show = showFilePicker, + onDismissRequest = { showFilePicker = false }, + onSelectSysDir = { + showFilePicker = false + try { + selectDocTree.launch(null) + } catch (e: Exception) { - } } - ) - } + } + ) - if (showCheckSourceSheet) { - CheckSourceBottomSheet( - viewModel = viewModel, - onDismiss = { showCheckSourceSheet = false } - ) - } + CheckSourceBottomSheet( + show = showCheckSourceSheet, + viewModel = viewModel, + onDismiss = { showCheckSourceSheet = false } + ) - if (showDirectLinkUploadSheet) { - DirectLinkUploadBottomSheet( - viewModel = viewModel, - onDismiss = { showDirectLinkUploadSheet = false } - ) - } + DirectLinkUploadBottomSheet( + show = showDirectLinkUploadSheet, + viewModel = viewModel, + onDismiss = { showDirectLinkUploadSheet = false } + ) if (showClearCacheDialog) { ConfirmDialog( diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt index fe143678f..52b6d9888 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt @@ -23,18 +23,19 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun PageKeySheet( + show: Boolean, onDismissRequest: () -> Unit ) { var prevKeys by remember { mutableStateOf(ReadConfig.prevKeys) } var nextKeys by remember { mutableStateOf(ReadConfig.nextKeys) } - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet(show = show, onDismissRequest = onDismissRequest) { Column( modifier = Modifier.Companion .fillMaxWidth() diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt index ebe4e064e..9b9456f36 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt @@ -320,7 +320,8 @@ fun ReadConfigScreen( } } - if (showPageKeySheet) { - PageKeySheet(onDismissRequest = { showPageKeySheet = false }) - } + PageKeySheet( + show = showPageKeySheet, + onDismissRequest = { showPageKeySheet = false } + ) } diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt index 2f19eb534..e1a95bff2 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt @@ -32,7 +32,7 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -40,6 +40,7 @@ import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun BackgroundImageManageSheet( + show: Boolean, isDarkTheme: Boolean, onDismissRequest: () -> Unit, viewModel: ThemeConfigViewModel = koinViewModel() @@ -65,7 +66,8 @@ fun BackgroundImageManageSheet( ThemeConfig.bgImageLight } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( @@ -140,14 +142,13 @@ fun BackgroundImageManageSheet( } } - if (showFilePicker) { - FilePickerSheet( - onDismissRequest = { showFilePicker = false }, - onSelectSysFile = { - selectImage.launch("image/*") - showFilePicker = false - }, - allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") - ) - } + FilePickerSheet( + show = showFilePicker, + onDismissRequest = { showFilePicker = false }, + onSelectSysFile = { + selectImage.launch("image/*") + showFilePicker = false + }, + allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") + ) } diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt index e273691ec..045d7fd84 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt @@ -39,7 +39,7 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.getCompatDrawable import splitties.init.appCtx @@ -47,6 +47,7 @@ import splitties.init.appCtx @OptIn(ExperimentalMaterial3Api::class) @Composable fun LauncherIconPickerSheet( + show: Boolean, selectedValue: String, onDismissRequest: () -> Unit, onValueChange: (String) -> Unit @@ -54,7 +55,8 @@ fun LauncherIconPickerSheet( val context = LocalContext.current val icons = LauncherIcons.list - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt index 2902d9631..4bcec4533 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt @@ -15,14 +15,14 @@ object ThemeConfig { var enableBlur by prefDelegate(PreferKey.enableBlur, false) - var enableProgressiveBlur by prefDelegate(PreferKey.enableProgressiveBlur, true) + var enableProgressiveBlur by prefDelegate(PreferKey.enableProgressiveBlur, false) var useFlexibleTopAppBar by prefDelegate(PreferKey.useFlexibleTopAppBar, true) var paletteStyle by prefDelegate(PreferKey.paletteStyle, "tonalSpot") //m3 or miuix - var composeEngine by prefDelegate(PreferKey.composeEngine, "m3") + var composeEngine by prefDelegate(PreferKey.composeEngine, "material") var materialVersion by prefDelegate(PreferKey.materialVersion, "material3") diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt index a3163414a..1047c885a 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box 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.fillMaxSize @@ -44,6 +45,7 @@ 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 @@ -95,6 +97,10 @@ import io.legado.app.utils.postEvent import io.legado.app.utils.restart import io.legado.app.utils.toastOnUi import org.koin.androidx.compose.koinViewModel +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 +import top.yukonga.miuix.kmp.basic.Text as MiuixText @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable @@ -137,9 +143,10 @@ fun ThemeConfigScreen( .verticalScroll(rememberScrollState()) .padding(16.dp) ) { - val composeEngine = remember { ThemeConfig.composeEngine } - val isMiuixEngine = - remember(composeEngine) { ThemeResolver.isMiuixEngine(composeEngine) } + val composeEngine = ThemeConfig.composeEngine + val isMiuixEngine = remember(composeEngine) { + ThemeResolver.isMiuixEngine(composeEngine) + } val isDarkTheme = when (selectedThemeMode) { "1" -> false "2" -> true @@ -169,6 +176,20 @@ fun ThemeConfigScreen( themeItems.zip(themeValues).toList() } + if (isMiuixEngine) { + MiuixCard( + cornerRadius = 16.dp, + insideMargin = PaddingValues(16.dp), + colors = MiuixCardDefaults.defaultColors( + color = MiuixTheme.colorScheme.primaryVariant, + contentColor = MiuixTheme.colorScheme.onPrimary + ) + ) { + MiuixText("Miuix 目前为测试主题,且不对基于View的界面生效!") + } + } + + SplicedColumnGroup(title = stringResource(R.string.theme)) { if (isMiuixEngine) { DropdownListSettingItem( @@ -253,7 +274,9 @@ fun ThemeConfigScreen( selectedValue = ThemeConfig.composeEngine, displayEntries = stringArrayResource(R.array.composeEngine), entryValues = stringArrayResource(R.array.composeEngine_value), - onValueChange = { ThemeConfig.composeEngine = it } + onValueChange = { + ThemeConfig.composeEngine = it + } ) SliderSettingItem( title = stringResource(R.string.font_scale), @@ -531,47 +554,46 @@ fun ThemeConfigScreen( manageKey?.let { isDark -> BackgroundImageManageSheet( + show = true, isDarkTheme = isDark, onDismissRequest = { manageKey = null } ) } - if (showColorPicker) { - ColorPickerSheet( - initialColor = primaryColorValue.value, - onDismissRequest = { showColorPicker = false }, - onColorSelected = { color -> - primaryColorValue.value = color - ThemeConfig.cPrimary = color - ThemeStore.editTheme(context) - .primaryColor(color) - .apply() - DynamicColors.applyToActivitiesIfAvailable( - context.applicationContext as android.app.Application, - DynamicColorsOptions.Builder() - .setContentBasedSource(context.primaryColor) - .build() - ) - } - ) - } - if (showLauncherIconPicker) { - LauncherIconPickerSheet( - selectedValue = ThemeConfig.launcherIcon, - onDismissRequest = { showLauncherIconPicker = false }, - onValueChange = { - ThemeConfig.launcherIcon = it - LauncherIconHelp.changeIcon(it) - } - ) - } + ColorPickerSheet( + show = showColorPicker, + initialColor = primaryColorValue.value, + onDismissRequest = { showColorPicker = false }, + onColorSelected = { color -> + primaryColorValue.value = color + ThemeConfig.cPrimary = color + ThemeStore.editTheme(context) + .primaryColor(color) + .apply() + DynamicColors.applyToActivitiesIfAvailable( + context.applicationContext as android.app.Application, + DynamicColorsOptions.Builder() + .setContentBasedSource(context.primaryColor) + .build() + ) + } + ) - if (showThemeListDialog) { - ThemeListDialog( - onDismissRequest = { showThemeListDialog = false } - ) - } + LauncherIconPickerSheet( + show = showLauncherIconPicker, + selectedValue = ThemeConfig.launcherIcon, + onDismissRequest = { showLauncherIconPicker = false }, + onValueChange = { + ThemeConfig.launcherIcon = it + LauncherIconHelp.changeIcon(it) + } + ) + + ThemeListDialog( + show = showThemeListDialog, + onDismissRequest = { showThemeListDialog = false } + ) saveThemeKey?.let { key -> AlertDialog( @@ -652,7 +674,7 @@ fun ThemeModeSelector( Spacer(Modifier.size(ToggleButtonDefaults.IconSpacing)) - AppText(text = label) + Text(text = label) } } } diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt index 13594b5d6..771065d75 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt @@ -38,7 +38,7 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.GSON import io.legado.app.utils.getClipText @@ -48,6 +48,7 @@ import io.legado.app.utils.toastOnUi @OptIn(ExperimentalMaterial3Api::class) @Composable fun ThemeListDialog( + show: Boolean, onDismissRequest: () -> Unit ) { val context = LocalContext.current @@ -55,7 +56,8 @@ fun ThemeListDialog( var deleteIndex by remember { mutableStateOf(null) } val themeList = remember(listVersion) { OldThemeConfig.configList.toList() } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt index 5d9f98ced..08145220d 100644 --- a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt @@ -36,7 +36,7 @@ import androidx.compose.ui.res.stringResource 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch @@ -56,7 +56,8 @@ fun DictRuleEditSheet( var showRule by remember(rule) { mutableStateOf(rule?.showRule ?: "") } var showMenu by remember { mutableStateOf(false) } - GlassModalBottomSheet( + AppModalBottomSheet( + show = true, onDismissRequest = onDismissRequest ) { Box( diff --git a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt index e157fd51d..b67c34077 100644 --- a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt +++ b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt @@ -5,7 +5,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -44,13 +43,11 @@ 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 import io.legado.app.ui.widget.components.card.ReorderableSelectionItem import io.legado.app.ui.widget.components.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.importComponents.BaseImportUiState import io.legado.app.ui.widget.components.importComponents.BatchImportDialog import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn @@ -153,54 +150,49 @@ fun DictRuleScreen( ) } - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - title = stringResource(R.string.export), - onSelectSysDir = { - showExportSheet = false - exportDoc.launch("exportDictRule.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + title = stringResource(R.string.export), + onSelectSysDir = { + showExportSheet = false + exportDoc.launch("exportDictRule.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_dict_rule), - onSelectSysFile = { types -> - importDoc.launch(types) - showImportSheet = false - }, - onManualInput = { - showUrlInput = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = "导入词典规则", - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - itemContent = { rule, _ -> - Column { - AppText(rule.name, style = LegadoTheme.typography.titleMedium) - AppText(rule.urlRule, style = LegadoTheme.typography.bodySmall, maxLines = 1) - } - } - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_dict_rule), + onSelectSysFile = { types -> + importDoc.launch(types) + showImportSheet = false + }, + onManualInput = { + showUrlInput = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) + + BatchImportDialog( + title = "导入词典规则", + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + itemTitle = { rule -> rule.name }, + itemSubtitle = { rule -> + rule.urlRule.takeIf { it.isNotBlank() } + } + ) LaunchedEffect(reorderableState.isAnyItemDragging) { if (!reorderableState.isAnyItemDragging) { @@ -228,47 +220,46 @@ fun DictRuleScreen( ) } - if (showEditSheet) { - RuleEditSheet( - rule = editingRule, - title = stringResource(R.string.dict_rule), - label1 = stringResource(R.string.url_rule), - label2 = stringResource(R.string.show_rule), - onDismissRequest = { - showEditSheet = false - editingRule = null - }, - onSave = { updatedRule -> - if (editingRule == null) { - viewModel.insert(updatedRule) - } else { - viewModel.update(updatedRule) - } - showEditSheet = false - editingRule = null - }, - onCopy = { viewModel.copyRule(it) }, - onPaste = { viewModel.pasteRule() }, - toFields = { r -> - RuleEditFields( - name = r?.name ?: "", - rule1 = r?.urlRule ?: "", - rule2 = r?.showRule ?: "" - ) - }, - fromFields = { fields, old -> - old?.copy( - name = fields.name, - urlRule = fields.rule1, - showRule = fields.rule2 - ) ?: DictRule( - name = fields.name, - urlRule = fields.rule1, - showRule = fields.rule2 - ) + RuleEditSheet( + show = showEditSheet, + rule = editingRule, + title = stringResource(R.string.dict_rule), + label1 = stringResource(R.string.url_rule), + label2 = stringResource(R.string.show_rule), + onDismissRequest = { + showEditSheet = false + editingRule = null + }, + onSave = { updatedRule -> + if (editingRule == null) { + viewModel.insert(updatedRule) + } else { + viewModel.update(updatedRule) } - ) - } + showEditSheet = false + editingRule = null + }, + onCopy = { viewModel.copyRule(it) }, + onPaste = { viewModel.pasteRule() }, + toFields = { r -> + RuleEditFields( + name = r?.name ?: "", + rule1 = r?.urlRule ?: "", + rule2 = r?.showRule ?: "" + ) + }, + fromFields = { fields, old -> + old?.copy( + name = fields.name, + urlRule = fields.rule1, + showRule = fields.rule2 + ) ?: DictRule( + name = fields.name, + urlRule = fields.rule1, + showRule = fields.rule2 + ) + } + ) RuleListScaffold( title = "字典规则", @@ -310,7 +301,7 @@ fun DictRuleScreen( snackbarHostState = snackbarHostState, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_str)) }, + text = stringResource(R.string.import_str), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) diff --git a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt index 2465c7f1d..1b19e510e 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.material3.WideNavigationRail import androidx.compose.material3.WideNavigationRailItem import androidx.compose.material3.WideNavigationRailValue @@ -195,7 +196,7 @@ fun MainScreen( ) { dismiss -> bookshelfUiState.groups.forEachIndexed { groupIndex, group -> RoundDropdownMenuItem( - text = { AppText(group.groupName) }, + text = group.groupName, onClick = { coroutineScope.launch { if (pagerState.currentPage != index) { @@ -321,7 +322,7 @@ private fun NavigationIcon( val icon = if (selected) destination.m3SelectedIcon else destination.m3Icon Box(modifier = modifier) { if (destination == MainDestination.Bookshelf && upBooksCount > 0) { - BadgedBox(badge = { Badge { AppText(upBooksCount.toString()) } }) { + BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) { Icon(icon, contentDescription = null) } } else { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt index 10c5bc5cd..89ded6312 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt @@ -31,38 +31,37 @@ 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.card.GlassCard +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet 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 fun BookshelfConfigSheet( + show: Boolean, onDismissRequest: () -> Unit ) { val configuration = LocalConfiguration.current val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet( + title = stringResource(R.string.bookshelf_layout), + show = show, + onDismissRequest = onDismissRequest + ) { + GlassCard() { + + } Column( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) .animateContentSize() - .padding(horizontal = 16.dp) .padding(bottom = 32.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - AppText( - text = stringResource(R.string.bookshelf_layout), - style = LegadoTheme.typography.titleLarge, - modifier = Modifier.padding(vertical = 16.dp) - ) - - // Group Style CompactDropdownSettingItem( title = stringResource(R.string.group_style), selectedValue = BookshelfConfig.bookGroupStyle.toString(), diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt index 76dcafcce..fcb17f4fa 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt @@ -40,12 +40,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Surface -import androidx.compose.material3.Tab -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 @@ -60,13 +57,11 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext 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 io.legado.app.R @@ -86,7 +81,8 @@ 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.ui.widget.components.tabRow.AppTabRow +import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.readText import io.legado.app.utils.startActivity import io.legado.app.utils.toastOnUi @@ -237,37 +233,37 @@ fun BookshelfScreen( topBarActions = { }, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.add_remote_book)) }, + text = stringResource(R.string.add_remote_book), onClick = { context.startActivity(); dismiss() }, leadingIcon = { Icon(Icons.Default.Wifi, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.book_local)) }, + text = stringResource(R.string.book_local), onClick = { context.startActivity(); dismiss() }, leadingIcon = { Icon(Icons.Default.Save, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.update_toc)) }, + text = stringResource(R.string.update_toc), onClick = { viewModel.upToc(uiState.items); dismiss() }, leadingIcon = { Icon(Icons.Default.Refresh, null) } ) RoundDropdownMenuItem( - text = { AppText("布局设置") }, + text = "布局设置", onClick = { showConfigSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.GridView, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.group_manage)) }, + text = stringResource(R.string.group_manage), onClick = { showGroupManageSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.Edit, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.add_url)) }, + text = stringResource(R.string.add_url), onClick = { showAddUrlDialog = true; dismiss() }, leadingIcon = { Icon(Icons.Default.Link, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.bookshelf_management)) }, + text = stringResource(R.string.bookshelf_management), onClick = { val groupId = uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L @@ -279,7 +275,7 @@ fun BookshelfScreen( leadingIcon = { Icon(Icons.Default.Settings, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.cache_export)) }, + text = stringResource(R.string.cache_export), onClick = { val groupId = uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L @@ -291,7 +287,7 @@ fun BookshelfScreen( leadingIcon = { Icon(Icons.Default.Download, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.export_bookshelf)) }, + text = stringResource(R.string.export_bookshelf), onClick = { showExportSheet = true dismiss() @@ -299,12 +295,12 @@ fun BookshelfScreen( leadingIcon = { Icon(Icons.Default.ImportExport, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_bookshelf)) }, + text = stringResource(R.string.import_bookshelf), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.log)) }, + text = stringResource(R.string.log), onClick = { showLogSheet = true dismiss() @@ -326,7 +322,7 @@ fun BookshelfScreen( uiState.groups.map { it.groupName } } - AdaptiveTabRow( + AppTabRow( tabTitles = tabTitles, selectedTabIndex = selectedTabIndex, onTabSelected = { index -> @@ -349,7 +345,7 @@ fun BookshelfScreen( ) { dismiss -> uiState.groups.forEachIndexed { index, group -> RoundDropdownMenuItem( - text = { AppText(group.groupName) }, + text = group.groupName, onClick = { scope.launch { pagerState.animateScrollToPage(index) } dismiss() @@ -487,13 +483,15 @@ fun BookshelfScreen( } } - if (showConfigSheet) { - BookshelfConfigSheet(onDismissRequest = { showConfigSheet = false }) - } + BookshelfConfigSheet( + show = showConfigSheet, + onDismissRequest = { showConfigSheet = false } + ) - if (showGroupManageSheet) { - GroupManageSheet(onDismissRequest = { showGroupManageSheet = false }) - } + GroupManageSheet( + show = showGroupManageSheet, + onDismissRequest = { showGroupManageSheet = false } + ) if (showAddUrlDialog) { SourceInputDialog( @@ -506,40 +504,39 @@ fun BookshelfScreen( ) } - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_bookshelf), - onSelectSysFile = { types -> - importLauncher.launch(types) - showImportSheet = false - }, - onManualInput = { - showAddUrlDialog = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_bookshelf), + onSelectSysFile = { types -> + importLauncher.launch(types) + showImportSheet = false + }, + onManualInput = { + showAddUrlDialog = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - title = stringResource(R.string.export_bookshelf), - onSelectSysDir = { - showExportSheet = false - exportLauncher.launch("bookshelf.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadBookshelf(uiState.items) - } - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + title = stringResource(R.string.export_bookshelf), + onSelectSysDir = { + showExportSheet = false + exportLauncher.launch("bookshelf.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadBookshelf(uiState.items) + } + ) - if (showLogSheet) { - AppLogSheet(onDismissRequest = { showLogSheet = false }) - } + AppLogSheet( + show = showLogSheet, + onDismissRequest = { showLogSheet = false } + ) if (uiState.isLoading) { Dialog(onDismissRequest = {}) { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt index 7149b5f13..0049f1095 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt @@ -6,18 +6,13 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -26,7 +21,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -35,10 +29,9 @@ 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.button.SmallIconButton 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.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.utils.move import org.koin.androidx.compose.koinViewModel import sh.calvin.reorderable.rememberReorderableLazyListState @@ -46,6 +39,7 @@ import sh.calvin.reorderable.rememberReorderableLazyListState @OptIn(ExperimentalMaterial3Api::class) @Composable fun GroupManageSheet( + show: Boolean, onDismissRequest: () -> Unit, viewModel: GroupViewModel = koinViewModel(), bookshelfViewModel: BookshelfViewModel = koinViewModel() @@ -78,7 +72,22 @@ fun GroupManageSheet( } } - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet( + show = show, + onDismissRequest = onDismissRequest, + title = if (!isEditing) stringResource(R.string.group_manage) else stringResource(R.string.group_edit), + endAction = { + if (!isEditing) { + SmallIconButton( + onClick = { + editingGroup = null + isEditing = true + }, + icon = Icons.Default.Add + ) + } + } + ) { AnimatedContent( targetState = isEditing, transitionSpec = { @@ -93,56 +102,28 @@ fun GroupManageSheet( viewModel = viewModel ) } else { - Column( - modifier = Modifier - .fillMaxWidth() + LazyColumn( + state = listState, + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp) ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(vertical = 8.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - AppText( - text = stringResource(R.string.group_manage), - style = LegadoTheme.typography.titleLarge + items(listData, key = { it.groupId }) { group -> + val manageNameInfo = remember(group) { group.getManageName(context) } + ReorderableSelectionItem( + state = reorderableState, + key = group.groupId, + title = group.groupName.ifBlank { manageNameInfo.suffix.orEmpty() }, + subtitle = if (group.groupName.isNotBlank()) manageNameInfo.suffix else null, + isEnabled = group.show, + containerColor = MaterialTheme.colorScheme.surface, + onEnabledChange = { isChecked -> + viewModel.upGroup(group.copy(show = isChecked)) + }, + onClickEdit = { + editingGroup = group + isEditing = true + } ) - IconButton(onClick = { - editingGroup = null - isEditing = true - }) { - Icon( - Icons.Default.Add, - contentDescription = stringResource(R.string.add) - ) - } - } - - LazyColumn( - state = listState, - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - items(listData, key = { it.groupId }) { group -> - val manageNameInfo = remember(group) { group.getManageName(context) } - ReorderableSelectionItem( - state = reorderableState, - key = group.groupId, - title = group.groupName.ifBlank { manageNameInfo.suffix.orEmpty() }, - subtitle = if (group.groupName.isNotBlank()) manageNameInfo.suffix else null, - isEnabled = group.show, - containerColor = MaterialTheme.colorScheme.surface, - onEnabledChange = { isChecked -> - viewModel.upGroup(group.copy(show = isChecked)) - }, - onClickEdit = { - editingGroup = group - isEditing = true - } - ) - } } } } diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt index 9be3376af..568183b80 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt @@ -153,13 +153,13 @@ fun ExploreScreen( dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Group) }, - text = { AppText(stringResource(R.string.all)) }, + text = stringResource(R.string.all), onClick = { viewModel.setGroup(""); dismiss() } ) uiState.groups.forEach { group -> RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) }, - text = { AppText(group) }, + text = group, onClick = { viewModel.setGroup(group); dismiss() } ) } @@ -416,29 +416,29 @@ fun ExploreSourceHeader( PillHeaderDivider(title = item.bookSourceName) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) }, - text = { AppText(stringResource(R.string.to_top)) }, + text = stringResource(R.string.to_top), onClick = { onTop(); showMenu = false } ) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Edit) }, - text = { AppText(stringResource(R.string.edit)) }, + text = stringResource(R.string.edit), onClick = { onEdit(); showMenu = false } ) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Search) }, - text = { AppText(stringResource(R.string.search)) }, + text = stringResource(R.string.search), onClick = { onSearch(); showMenu = false } ) if (item.hasLoginUrl) { RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) }, - text = { AppText(stringResource(R.string.login)) }, + text = stringResource(R.string.login), onClick = { onLogin(); showMenu = false } ) } RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Refresh) }, - text = { AppText(stringResource(R.string.refresh)) }, + text = stringResource(R.string.refresh), onClick = { onRefresh(); showMenu = false } ) RoundDropdownMenuItem( @@ -448,12 +448,8 @@ fun ExploreSourceHeader( tint = MaterialTheme.colorScheme.error ) }, - text = { - AppText( - stringResource(R.string.delete), - color = MaterialTheme.colorScheme.error - ) - }, + text = stringResource(R.string.delete), + color = LegadoTheme.colorScheme.error, onClick = { onDelete(); showMenu = false } ) } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt b/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt index f752583fa..d1a63d6d8 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt @@ -239,7 +239,7 @@ fun WebServiceSettingBlock( Row( modifier = Modifier .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp, bottom = 12.dp), + .padding(start = 16.dp, end = 16.dp, top = 12.dp, bottom = 12.dp), horizontalArrangement = Arrangement.End ) { SmallTextButton( diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt index 3a25954cf..fed5dab27 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt @@ -136,12 +136,12 @@ fun RssScreen( dismiss() }, leadingIcon = { MenuItemIcon(Icons.Default.Settings) }, - text = { AppText("订阅源管理") } + text = "订阅源管理" ) PillDivider() RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Group) }, - text = { AppText(stringResource(R.string.all)) }, + text = stringResource(R.string.all), onClick = { viewModel.setGroup("") dismiss() @@ -150,7 +150,7 @@ fun RssScreen( uiState.groups.forEach { group -> RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) }, - text = { AppText(group) }, + text = group, onClick = { viewModel.setGroup(group) dismiss() @@ -247,7 +247,7 @@ fun RssSourceGridItem( PillHeaderDivider(title = source.sourceName) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) }, - text = { AppText(stringResource(R.string.to_top)) }, + text = stringResource(R.string.to_top), onClick = { onTop() showMenu = false @@ -255,7 +255,7 @@ fun RssSourceGridItem( ) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Edit) }, - text = { AppText(stringResource(R.string.edit)) }, + text = stringResource(R.string.edit), onClick = { onEdit() showMenu = false @@ -264,7 +264,7 @@ fun RssSourceGridItem( if (!source.loginUrl.isNullOrBlank()) { RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) }, - text = { AppText(stringResource(R.string.login)) }, + text = stringResource(R.string.login), onClick = { onLogin() showMenu = false @@ -273,7 +273,7 @@ fun RssSourceGridItem( } RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Close) }, - text = { AppText(stringResource(R.string.disable_source)) }, + text = stringResource(R.string.disable_source), onClick = { onDisable() showMenu = false @@ -286,12 +286,8 @@ fun RssSourceGridItem( tint = MaterialTheme.colorScheme.error ) }, - text = { - AppText( - stringResource(R.string.delete), - color = MaterialTheme.colorScheme.error - ) - }, + text = stringResource(R.string.delete), + color = MaterialTheme.colorScheme.error, onClick = { onDelete() showMenu = false diff --git a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt index 3cb2cf8f2..a254da5b2 100644 --- a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt +++ b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt @@ -8,7 +8,6 @@ import androidx.compose.animation.SharedTransitionScope import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -19,7 +18,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.FileOpen import androidx.compose.material3.AlertDialog -import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FloatingActionButton @@ -57,7 +55,6 @@ 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 @@ -70,7 +67,7 @@ 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.tabRow.AppTabRow import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -161,56 +158,48 @@ fun ReplaceRuleScreen( ) } - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_replace_rule), - onSelectSysFile = { types -> - importDoc.launch(types) - showImportSheet = false - }, - onManualInput = { - showUrlInput = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_replace_rule), + onSelectSysFile = { types -> + importDoc.launch(types) + showImportSheet = false + }, + onManualInput = { + showUrlInput = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - onSelectSysDir = { - showExportSheet = false - exportDoc.launch("exportReplaceRule.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + onSelectSysDir = { + showExportSheet = false + exportDoc.launch("exportReplaceRule.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = stringResource(R.string.import_replace_rule), - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - topBarActions = {}, - itemContent = { rule, _ -> - Column { - AppText(rule.name, style = LegadoTheme.typography.titleMedium) - if (!rule.group.isNullOrBlank()) { - AppText(rule.group!!, style = LegadoTheme.typography.bodySmall) - } - } - } - ) - } + BatchImportDialog( + title = stringResource(R.string.import_replace_rule), + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + topBarActions = {}, + itemTitle = { rule -> rule.name }, + itemSubtitle = { rule -> + rule.group?.takeIf { it.isNotBlank() } + } + ) if (importState is BaseImportUiState.Loading) { Dialog(onDismissRequest = { viewModel.cancelImport() }) { LoadingIndicator() } @@ -263,14 +252,15 @@ fun ReplaceRuleScreen( } } - if (showGroupManageSheet) { - GroupManageBottomSheet( - groups = groups, - onDismissRequest = { showGroupManageSheet = false }, - onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, - onDeleteGroup = { viewModel.delGroup(it) } - ) - } + + GroupManageBottomSheet( + show = showGroupManageSheet, + groups = groups, + onDismissRequest = { showGroupManageSheet = false }, + onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, + onDeleteGroup = { viewModel.delGroup(it) } + ) + showDeleteRuleDialog?.let { rule -> AlertDialog( @@ -343,7 +333,7 @@ fun ReplaceRuleScreen( }, bottomContent = { if (tabItems.size > 1) { - AdaptiveTabRow( + AppTabRow( tabTitles = tabItems, selectedTabIndex = selectedTabIndex, onTabSelected = { index -> @@ -384,29 +374,29 @@ fun ReplaceRuleScreen( snackbarHostState = snackbarHostState, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_str)) }, + text = stringResource(R.string.import_str), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) RoundDropdownMenuItem( - text = { AppText("分组管理") }, + text = "分组管理", onClick = { showGroupManageSheet = true; dismiss() } ) RoundDropdownMenuItem( - text = { AppText("帮助") }, + text = "帮助", onClick = { /*TODO*/ dismiss() } ) PillDivider() RoundDropdownMenuItem( - text = { AppText("旧的在前") }, + text = "旧的在前", onClick = { viewModel.setSortMode("asc"); dismiss() } ) RoundDropdownMenuItem( - text = { AppText("新的在前") }, + text = "新的在前", onClick = { viewModel.setSortMode("desc"); dismiss() } ) RoundDropdownMenuItem( - text = { AppText("名称升序") }, + text = "名称升序", onClick = { viewModel.setSortMode("name_asc") dismiss() @@ -416,7 +406,7 @@ fun ReplaceRuleScreen( } ) RoundDropdownMenuItem( - text = { AppText("名称降序") }, + text = "名称降序", onClick = { viewModel.setSortMode("name_desc") dismiss() @@ -473,16 +463,16 @@ fun ReplaceRuleScreen( //clipInOverlayDuringTransition = OverlayClip(RoundedCornerShape(12.dp)) ), dropdownContent = { dismiss -> - DropdownMenuItem( - text = { AppText("移至顶部") }, + RoundDropdownMenuItem( + text = "移至顶部", onClick = { viewModel.toTop(ui.rule); dismiss() } ) - DropdownMenuItem( - text = { AppText("移至底部") }, + RoundDropdownMenuItem( + text = "移至底部", onClick = { viewModel.toBottom(ui.rule); dismiss() } ) - DropdownMenuItem( - text = { AppText("删除") }, + RoundDropdownMenuItem( + text = "删除", onClick = { showDeleteRuleDialog = ui.rule; dismiss() } ) } diff --git a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt index 3cc61f0e2..2cdc02946 100644 --- a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt +++ b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt @@ -3,11 +3,9 @@ package io.legado.app.ui.rss.favorites import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons @@ -44,7 +42,6 @@ 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) @@ -129,11 +126,10 @@ fun RssFavoritesScreen( topBarActions = {}, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { + text = stringResource(R.string.all), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Default.Group, null, modifier = Modifier.size(18.dp)) - Spacer(Modifier.width(12.dp)) - AppText(stringResource(R.string.all)) } }, onClick = { @@ -143,15 +139,14 @@ fun RssFavoritesScreen( ) groups.forEach { group -> RoundDropdownMenuItem( - text = { + text = group, + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon( Icons.AutoMirrored.Outlined.Label, null, modifier = Modifier.size(18.dp) ) - Spacer(Modifier.width(12.dp)) - AppText(group) } }, onClick = { @@ -162,11 +157,10 @@ fun RssFavoritesScreen( } PillDivider() RoundDropdownMenuItem( - text = { + text = stringResource(R.string.delete_select_group), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Default.DeleteSweep, null, modifier = Modifier.size(18.dp)) - Spacer(Modifier.width(12.dp)) - AppText(stringResource(R.string.delete_select_group)) } }, onClick = { @@ -175,11 +169,10 @@ fun RssFavoritesScreen( } ) RoundDropdownMenuItem( - text = { + text = stringResource(R.string.all), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Default.DeleteForever, null, modifier = Modifier.size(18.dp)) - Spacer(Modifier.width(12.dp)) - AppText(stringResource(R.string.all)) } }, onClick = { @@ -248,14 +241,14 @@ fun RssFavoritesScreen( }, dropdownContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.change_group)) }, + text = stringResource(R.string.change_group), onClick = { showSetGroupDialog = rssStar dismiss() } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.delete)) }, + text = stringResource(R.string.delete), onClick = { viewModel.deleteStar(rssStar) dismiss() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt index ee194858c..513cf214b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt @@ -5,7 +5,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -41,7 +40,6 @@ 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 @@ -50,7 +48,6 @@ import io.legado.app.ui.widget.components.card.ReorderableSelectionItem 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.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.importComponents.BaseImportUiState import io.legado.app.ui.widget.components.importComponents.BatchImportDialog import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn @@ -175,50 +172,41 @@ fun RssSourceScreen( ) } - if (showGroupManageSheet) { - GroupManageBottomSheet( - groups = groups, - onDismissRequest = { showGroupManageSheet = false }, - onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, - onDeleteGroup = { viewModel.delGroup(it) } - ) - } + GroupManageBottomSheet( + show = showGroupManageSheet, + groups = groups, + onDismissRequest = { showGroupManageSheet = false }, + onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, + onDeleteGroup = { viewModel.delGroup(it) } + ) - if (showFilePickerSheet) { - FilePickerSheet( - onDismissRequest = { showFilePickerSheet = false }, - onSelectSysDir = { - showFilePickerSheet = false - exportDoc.launch("exportRssSource.json") - }, - onUpload = { - showFilePickerSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = stringResource(R.string.import_rss_source), - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - itemContent = { source, _ -> - Column { - AppText(source.sourceName, style = LegadoTheme.typography.titleMedium) - AppText( - source.sourceUrl, - style = LegadoTheme.typography.bodySmall, - maxLines = 1 - ) - } - } - ) - } + FilePickerSheet( + show = showFilePickerSheet, + onDismissRequest = { showFilePickerSheet = false }, + onSelectSysDir = { + showFilePickerSheet = false + exportDoc.launch("exportRssSource.json") + }, + onUpload = { + showFilePickerSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) + + BatchImportDialog( + title = stringResource(R.string.import_rss_source), + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + itemTitle = { rule -> rule.sourceName }, + itemSubtitle = { rule -> + rule.sourceUrl.takeIf { it.isNotBlank() } + } + ) LaunchedEffect(reorderableState.isAnyItemDragging) { if (!reorderableState.isAnyItemDragging) { @@ -291,11 +279,11 @@ fun RssSourceScreen( dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( onClick = { showGroupManageSheet = true }, - text = { AppText("分组管理") }, + text = "分组管理", ) Box { RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_rss_source)) }, + text = stringResource(R.string.import_rss_source), onClick = { showImportMenu = true } ) RoundDropdownMenu( @@ -303,7 +291,7 @@ fun RssSourceScreen( onDismissRequest = { showImportMenu = false } ) { RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_on_line)) }, + text = stringResource(R.string.import_on_line), onClick = { showImportMenu = false dismiss() @@ -311,7 +299,7 @@ fun RssSourceScreen( } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_local)) }, + text = stringResource(R.string.import_local), onClick = { showImportMenu = false dismiss() @@ -319,7 +307,7 @@ fun RssSourceScreen( } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_default_rule)) }, + text = stringResource(R.string.import_default_rule), onClick = { showImportMenu = false dismiss() @@ -330,29 +318,29 @@ fun RssSourceScreen( } PillDivider() RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.all)) }, + text = stringResource(R.string.all), onClick = { dismiss(); viewModel.setGroupFilter(null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.enabled)) }, + text = stringResource(R.string.enabled), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_ENABLED) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.disabled)) }, + text = stringResource(R.string.disabled), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_DISABLED) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.need_login)) }, + text = stringResource(R.string.need_login), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_LOGIN) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.no_group)) }, + text = stringResource(R.string.no_group), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_NO_GROUP) } ) PillDivider() groups.forEach { group -> RoundDropdownMenuItem( - text = { AppText(group) }, + text = group, onClick = { dismiss(); viewModel.setGroupFilter("${RssSourceViewModel.PREFIX_GROUP}$group") } ) } diff --git a/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt b/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt index 0da339c1e..b3894acd9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt +++ b/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt @@ -89,7 +89,8 @@ fun RuleSubScreen( topBarActions = {}, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { + text = stringResource(R.string.sort), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.AutoMirrored.Filled.Sort, null, modifier = Modifier.size(18.dp)) Spacer(Modifier.size(12.dp)) @@ -185,7 +186,7 @@ fun RuleSubScreen( }, dropdownContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.delete)) }, + text = stringResource(R.string.delete), onClick = { viewModel.delete(ruleSub) dismiss() diff --git a/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt b/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt index cac926249..88039c0ca 100644 --- a/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt +++ b/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight import io.legado.app.ui.config.themeConfig.ThemeConfig import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.theme.ThemeController @@ -46,8 +47,15 @@ fun AppTheme( ) } - val themeColors = remember(colorScheme, darkTheme, seedColor, paletteStyle, colorSchemeMode) { - LegadoThemeColors( + val themeColors = remember( + colorScheme, + darkTheme, + seedColor, + paletteStyle, + colorSchemeMode, + composeEngine + ) { + LegadoThemeMode( colorScheme = colorScheme, isDark = darkTheme, seedColor = seedColor, @@ -61,45 +69,230 @@ fun AppTheme( CompositionLocalProvider( LocalLegadoThemeColors provides themeColors ) { - when { - ThemeResolver.isMiuixEngine(themeColors.composeEngine) -> { - val controller = remember(colorSchemeMode, darkTheme) { - ThemeController( - colorSchemeMode = colorSchemeMode, - isDark = darkTheme + if (ThemeResolver.isMiuixEngine(themeColors.composeEngine)) { + val controller = remember(colorSchemeMode, darkTheme) { + ThemeController(colorSchemeMode = colorSchemeMode, isDark = darkTheme) + } + + MiuixTheme(controller = controller) { + val miuixStyles = MiuixTheme.textStyles + val legadoTypography = remember(miuixStyles) { + LegadoTypography( + headlineLarge = miuixStyles.title1, + headlineLargeEmphasized = miuixStyles.title1.copy(fontWeight = FontWeight.Medium), + headlineMedium = miuixStyles.title2, + headlineMediumEmphasized = miuixStyles.title2.copy(fontWeight = FontWeight.Medium), + headlineSmall = miuixStyles.title3, + headlineSmallEmphasized = miuixStyles.title3.copy(fontWeight = FontWeight.Medium), + + + titleLarge = miuixStyles.headline1, + titleLargeEmphasized = miuixStyles.headline1.copy(fontWeight = FontWeight.Medium), + titleMedium = miuixStyles.headline2, + titleMediumEmphasized = miuixStyles.headline2.copy(fontWeight = FontWeight.Medium), + titleSmall = miuixStyles.subtitle, + titleSmallEmphasized = miuixStyles.subtitle.copy(fontWeight = FontWeight.Medium), + + + bodyLarge = miuixStyles.paragraph, + bodyLargeEmphasized = miuixStyles.paragraph.copy(fontWeight = FontWeight.Medium), + bodyMedium = miuixStyles.body1, + bodyMediumEmphasized = miuixStyles.body1.copy(fontWeight = FontWeight.Medium), + bodySmall = miuixStyles.body2, + bodySmallEmphasized = miuixStyles.body2.copy(fontWeight = FontWeight.Medium), + + labelLarge = miuixStyles.button, + labelLargeEmphasized = miuixStyles.button.copy(fontWeight = FontWeight.Medium), + labelMedium = miuixStyles.footnote1, + labelMediumEmphasized = miuixStyles.footnote1.copy(fontWeight = FontWeight.Medium), + labelSmall = miuixStyles.footnote2, + labelSmallEmphasized = miuixStyles.footnote2.copy(fontWeight = FontWeight.Medium) ) } - MiuixTheme( - controller = controller - ) { - val miuixTextStyles = MiuixTheme.textStyles - val mappedTypography = remember(miuixTextStyles) { - miuixStylesToM3Typography(miuixTextStyles) - } + val miuixColorScheme = MiuixTheme.colorScheme - CompositionLocalProvider( - LocalLegadoTypography provides mappedTypography - ) { - AppBackground(darkTheme = darkTheme) { - content() - } - } + val mappedColorScheme = remember(miuixColorScheme) { + LegadoColorScheme( + primary = miuixColorScheme.primary, + onPrimary = miuixColorScheme.onPrimary, + primaryContainer = miuixColorScheme.primaryContainer, + onPrimaryContainer = miuixColorScheme.onPrimaryContainer, + inversePrimary = miuixColorScheme.primaryVariant, + + secondary = miuixColorScheme.primary.copy(alpha = 0.5f), + onSecondary = miuixColorScheme.onPrimary.copy(alpha = 0.5f), + secondaryContainer = miuixColorScheme.primaryContainer.copy(alpha = 0.5f), + onSecondaryContainer = miuixColorScheme.onPrimaryContainer.copy(alpha = 0.5f), + + tertiary = miuixColorScheme.secondary, + onTertiary = miuixColorScheme.onSecondary, + tertiaryContainer = miuixColorScheme.secondaryContainer, + onTertiaryContainer = miuixColorScheme.onSecondaryContainer, + + // ================= 4. 背景与表面 (Background & Surface) ================= + background = miuixColorScheme.background, + onBackground = miuixColorScheme.onBackground, + + surface = miuixColorScheme.surface, + onSurface = miuixColorScheme.onSurface, + surfaceVariant = miuixColorScheme.surfaceVariant, + // M3 的 onSurfaceVariant 通常是次级文字色。Miuix 的 onSurfaceSecondary 完美契合这个语义 + onSurfaceVariant = miuixColorScheme.onSurfaceSecondary, + + // M3 中用于给 Surface 叠加一层极淡主题色的属性,通常直接取 primary + surfaceTint = miuixColorScheme.primary, + + // Inverse 系列通常用于深色模式下的反色提示(如 Snackbar)。 + // 简单映射法:直接用现有的 onSurface 和 surface 交叉互换。 + inverseSurface = miuixColorScheme.onSurface, + inverseOnSurface = miuixColorScheme.surface, + + // ================= 5. 错误状态 (Error) ================= + error = miuixColorScheme.error, + onError = miuixColorScheme.onError, + errorContainer = miuixColorScheme.errorContainer, + onErrorContainer = miuixColorScheme.onErrorContainer, + + // ================= 6. 边框、分割线与遮罩 (Outline & Scrim) ================= + outline = miuixColorScheme.outline, + // outlineVariant 在 M3 中常用于分割线。Miuix 刚好有 dividerLine + outlineVariant = miuixColorScheme.dividerLine, + // scrim 是 M3 的遮罩层(如弹窗背后的阴影)。Miuix 刚好有 windowDimming + scrim = miuixColorScheme.windowDimming, + + surfaceBright = miuixColorScheme.surface, // Miuix 缺省,用 surface 兜底 + surfaceDim = miuixColorScheme.background, // Miuix 缺省,用 background 兜底 + surfaceContainer = miuixColorScheme.surfaceContainer, + surfaceContainerHigh = miuixColorScheme.surfaceContainerHigh, + surfaceContainerHighest = miuixColorScheme.surfaceContainerHighest, + surfaceContainerLow = miuixColorScheme.secondaryContainer, + surfaceContainerLowest = miuixColorScheme.background, + + primaryFixed = miuixColorScheme.primaryContainer, + primaryFixedDim = miuixColorScheme.primary, + onPrimaryFixed = miuixColorScheme.onPrimaryContainer, + onPrimaryFixedVariant = miuixColorScheme.onPrimary, + secondaryFixed = miuixColorScheme.secondaryContainer, + secondaryFixedDim = miuixColorScheme.secondary, + onSecondaryFixed = miuixColorScheme.onSecondaryContainer, + onSecondaryFixedVariant = miuixColorScheme.onSecondary, + tertiaryFixed = miuixColorScheme.tertiaryContainer, + tertiaryFixedDim = miuixColorScheme.tertiaryContainerVariant, + onTertiaryFixed = miuixColorScheme.onTertiaryContainer, + onTertiaryFixedVariant = miuixColorScheme.onTertiaryContainer + ) + } + + CompositionLocalProvider( + LocalLegadoTypography provides legadoTypography, + LocalLegadoColorScheme provides mappedColorScheme + ) { + AppBackground(darkTheme = darkTheme) { content() } } } + } else { + val Typography = Typography() + MaterialExpressiveTheme( + colorScheme = colorScheme, + typography = Typography, + motionScheme = MotionScheme.expressive(), + shapes = Shapes() + ) { + val legadoTypography = remember(Typography) { + LegadoTypography( + headlineLarge = Typography.headlineLarge, + headlineLargeEmphasized = Typography.headlineLargeEmphasized, + headlineMedium = Typography.headlineMedium, + headlineMediumEmphasized = Typography.headlineMediumEmphasized, + headlineSmall = Typography.headlineSmall, + headlineSmallEmphasized = Typography.headlineSmallEmphasized, - else -> { - MaterialExpressiveTheme( - colorScheme = colorScheme, - typography = Typography(), - motionScheme = MotionScheme.expressive(), - shapes = Shapes() + + titleLarge = Typography.titleLarge, + titleLargeEmphasized = Typography.titleLargeEmphasized, + titleMedium = Typography.titleMedium, + titleMediumEmphasized = Typography.titleMediumEmphasized, + titleSmall = Typography.titleSmall, + titleSmallEmphasized = Typography.titleSmallEmphasized, + + + bodyLarge = Typography.bodyLarge, + bodyLargeEmphasized = Typography.bodyLargeEmphasized, + bodyMedium = Typography.bodyMedium, + bodyMediumEmphasized = Typography.bodyMediumEmphasized, + bodySmall = Typography.bodySmall, + bodySmallEmphasized = Typography.bodySmallEmphasized, + + labelLarge = Typography.labelLarge, + labelLargeEmphasized = Typography.labelLargeEmphasized, + labelMedium = Typography.labelMedium, + labelMediumEmphasized = Typography.labelMediumEmphasized, + labelSmall = Typography.labelSmall, + labelSmallEmphasized = Typography.labelSmallEmphasized + ) + } + + val semanticColors = remember(colorScheme) { + LegadoColorScheme( + primary = colorScheme.primary, + onPrimary = colorScheme.onPrimary, + primaryContainer = colorScheme.primaryContainer, + onPrimaryContainer = colorScheme.onPrimaryContainer, + inversePrimary = colorScheme.inversePrimary, + secondary = colorScheme.secondary, + onSecondary = colorScheme.onSecondary, + secondaryContainer = colorScheme.secondaryContainer, + onSecondaryContainer = colorScheme.onSecondaryContainer, + tertiary = colorScheme.tertiary, + onTertiary = colorScheme.onTertiary, + tertiaryContainer = colorScheme.tertiaryContainer, + onTertiaryContainer = colorScheme.onTertiaryContainer, + background = colorScheme.background, + onBackground = colorScheme.onBackground, + surface = colorScheme.surface, + onSurface = colorScheme.onSurface, + surfaceVariant = colorScheme.surfaceVariant, + onSurfaceVariant = colorScheme.onSurfaceVariant, + surfaceTint = colorScheme.surfaceTint, + inverseSurface = colorScheme.inverseSurface, + inverseOnSurface = colorScheme.inverseOnSurface, + error = colorScheme.error, + onError = colorScheme.onError, + errorContainer = colorScheme.errorContainer, + onErrorContainer = colorScheme.onErrorContainer, + outline = colorScheme.outline, + outlineVariant = colorScheme.outlineVariant, + scrim = colorScheme.scrim, + surfaceBright = colorScheme.surfaceBright, + surfaceDim = colorScheme.surfaceDim, + surfaceContainer = colorScheme.surfaceContainer, + surfaceContainerHigh = colorScheme.surfaceContainerHigh, + surfaceContainerHighest = colorScheme.surfaceContainerHighest, + surfaceContainerLow = colorScheme.surfaceContainerLow, + surfaceContainerLowest = colorScheme.surfaceContainerLowest, + primaryFixed = colorScheme.primaryFixed, + primaryFixedDim = colorScheme.primaryFixedDim, + onPrimaryFixed = colorScheme.onPrimaryFixed, + onPrimaryFixedVariant = colorScheme.onPrimaryFixedVariant, + secondaryFixed = colorScheme.secondaryFixed, + secondaryFixedDim = colorScheme.secondaryFixedDim, + onSecondaryFixed = colorScheme.onSecondaryFixed, + onSecondaryFixedVariant = colorScheme.onSecondaryFixedVariant, + tertiaryFixed = colorScheme.tertiaryFixed, + tertiaryFixedDim = colorScheme.tertiaryFixedDim, + onTertiaryFixed = colorScheme.onTertiaryFixed, + onTertiaryFixedVariant = colorScheme.onTertiaryFixedVariant + ) + } + + CompositionLocalProvider( + LocalLegadoTypography provides legadoTypography, + LocalLegadoColorScheme provides semanticColors ) { - AppBackground(darkTheme = darkTheme) { - content() - } + AppBackground(darkTheme = darkTheme) { content() } } } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt b/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt index 292c2d277..b8d91d055 100644 --- a/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt +++ b/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt @@ -1,18 +1,18 @@ 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 androidx.compose.ui.text.TextStyle import com.materialkolor.PaletteStyle import dev.chrisbanes.haze.HazeState import top.yukonga.miuix.kmp.theme.ColorSchemeMode -data class LegadoThemeColors( +data class LegadoThemeMode( val colorScheme: ColorScheme, val isDark: Boolean, val seedColor: Color, @@ -22,30 +22,117 @@ data class LegadoThemeColors( val composeEngine: String, ) +data class LegadoColorScheme( + val primary: Color, + val onPrimary: Color, + val primaryContainer: Color, + val onPrimaryContainer: Color, + val inversePrimary: Color, + val secondary: Color, + val onSecondary: Color, + val secondaryContainer: Color, + val onSecondaryContainer: Color, + val tertiary: Color, + val onTertiary: Color, + val tertiaryContainer: Color, + val onTertiaryContainer: Color, + val background: Color, + val onBackground: Color, + val surface: Color, + val onSurface: Color, + val surfaceVariant: Color, + val onSurfaceVariant: Color, + val surfaceTint: Color, + val inverseSurface: Color, + val inverseOnSurface: Color, + val error: Color, + val onError: Color, + val errorContainer: Color, + val onErrorContainer: Color, + val outline: Color, + val outlineVariant: Color, + val scrim: Color, + val surfaceBright: Color, + val surfaceDim: Color, + val surfaceContainer: Color, + val surfaceContainerHigh: Color, + val surfaceContainerHighest: Color, + val surfaceContainerLow: Color, + val surfaceContainerLowest: Color, + val primaryFixed: Color, + val primaryFixedDim: Color, + val onPrimaryFixed: Color, + val onPrimaryFixedVariant: Color, + val secondaryFixed: Color, + val secondaryFixedDim: Color, + val onSecondaryFixed: Color, + val onSecondaryFixedVariant: Color, + val tertiaryFixed: Color, + val tertiaryFixedDim: Color, + val onTertiaryFixed: Color, + val onTertiaryFixedVariant: Color, +) + +data class LegadoTypography( + val headlineLarge: TextStyle, + val headlineLargeEmphasized: TextStyle, + val headlineMedium: TextStyle, + val headlineMediumEmphasized: TextStyle, + val headlineSmall: TextStyle, + val headlineSmallEmphasized: TextStyle, + + val titleLarge: TextStyle, + val titleLargeEmphasized: TextStyle, + val titleMedium: TextStyle, + val titleMediumEmphasized: TextStyle, + val titleSmall: TextStyle, + val titleSmallEmphasized: TextStyle, + + + val bodyLarge: TextStyle, + val bodyLargeEmphasized: TextStyle, + val bodyMedium: TextStyle, + val bodyMediumEmphasized: TextStyle, + val bodySmall: TextStyle, + val bodySmallEmphasized: TextStyle, + + val labelLarge: TextStyle, + val labelLargeEmphasized: TextStyle, + val labelMedium: TextStyle, + val labelMediumEmphasized: TextStyle, + val labelSmall: TextStyle, + val labelSmallEmphasized: TextStyle, + + ) + +val LocalLegadoColorScheme = staticCompositionLocalOf { + error("No ColorScheme provided") +} + +val LocalLegadoTypography = staticCompositionLocalOf { + error("No Typography provided") +} + val LocalLegadoThemeColors = staticCompositionLocalOf { - LegadoThemeColors( + LegadoThemeMode( colorScheme = lightColorScheme(), isDark = false, seedColor = Color.Unspecified, paletteStyle = PaletteStyle.TonalSpot, themeMode = ColorSchemeMode.System, useDynamicColor = true, - composeEngine = "m3" + composeEngine = "material" ) } -val LocalLegadoTypography = staticCompositionLocalOf { - Typography() -} - val LocalHazeState = compositionLocalOf { null } object LegadoTheme { - val colorScheme: ColorScheme + val colorScheme: LegadoColorScheme @Composable @ReadOnlyComposable - get() = LocalLegadoThemeColors.current.colorScheme + get() = LocalLegadoColorScheme.current val isDark: Boolean @Composable @@ -77,7 +164,7 @@ object LegadoTheme { @ReadOnlyComposable get() = LocalLegadoThemeColors.current.useDynamicColor - val typography: Typography + val typography: LegadoTypography @Composable @ReadOnlyComposable get() = LocalLegadoTypography.current diff --git a/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt b/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt index 0d3370e7a..4e2b0c773 100644 --- a/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt +++ b/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt @@ -66,7 +66,8 @@ object ThemeManager { } AppThemeMode.CUSTOM -> { - CustomColorScheme(context.primaryColor, style) + val colorSpec = ThemeResolver.resolveColorSpecFromMaterialVersion(materialVersion) + CustomColorScheme(context.primaryColor, style, colorSpec) .getColorScheme(darkTheme) } @@ -93,4 +94,4 @@ object ThemeManager { return scheme } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt b/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt index 226185e92..20ae7b087 100644 --- a/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt +++ b/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt @@ -67,4 +67,12 @@ object ThemeResolver { } } + fun resolveColorSpecFromMaterialVersion(value: String?): ThemeColorSpec { + return when (value) { + "material3Expressive" -> ThemeColorSpec.SPEC_2025 + "material3" -> ThemeColorSpec.SPEC_2021 + else -> ThemeColorSpec.SPEC_2021 + } + } + } diff --git a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt b/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt index 70d3ec548..98e3879df 100644 --- a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt +++ b/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt @@ -8,8 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandMore -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -22,26 +20,26 @@ 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.card.GlassCard import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun CollapsibleHeader( modifier: Modifier = Modifier, + showIcon: Boolean = true, isCollapsed: Boolean, onToggle: () -> Unit, title: String, subtitle: String? = null, titleContent: (@Composable ColumnScope.() -> Unit)? = null ) { - Card( + GlassCard( modifier = modifier .fillMaxWidth() .padding(start = 16.dp, top = 4.dp, end = 16.dp), shape = MaterialTheme.shapes.medium, - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surfaceContainer - ), + containerColor = LegadoTheme.colorScheme.surfaceContainer, onClick = onToggle ) { Row( @@ -59,7 +57,7 @@ fun CollapsibleHeader( text = title, style = LegadoTheme.typography.bodySmallEmphasized.copy( fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.primary + color = LegadoTheme.colorScheme.primary ), maxLines = 1, overflow = TextOverflow.Ellipsis @@ -68,7 +66,7 @@ fun CollapsibleHeader( AppText( text = it, style = LegadoTheme.typography.labelSmallEmphasized.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant + color = LegadoTheme.colorScheme.onSurfaceVariant ), maxLines = 1, overflow = TextOverflow.Ellipsis @@ -82,12 +80,14 @@ fun CollapsibleHeader( label = "arrowRotation" ) - Icon( - imageVector = Icons.Default.ExpandMore, - contentDescription = if (isCollapsed) "展开" else "折叠", - modifier = Modifier.rotate(rotation), - tint = MaterialTheme.colorScheme.primary - ) + if (showIcon) { + Icon( + imageVector = Icons.Default.ExpandMore, + contentDescription = if (isCollapsed) "展开" else "折叠", + modifier = Modifier.rotate(rotation), + tint = LegadoTheme.colorScheme.primary + ) + } } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt deleted file mode 100644 index 4c6d5b557..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt +++ /dev/null @@ -1,49 +0,0 @@ -package io.legado.app.ui.widget.components - - -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 androidx.compose.material3.LocalContentColor as MaterialLocalContentColor -import top.yukonga.miuix.kmp.basic.Icon as MiuixIcon -import top.yukonga.miuix.kmp.theme.LocalContentColor as MiuixLocalContentColor - -@Composable -fun AppIcon( - imageVector: ImageVector, - contentDescription: String?, - modifier: Modifier = Modifier, - tint: Color = currentContentColor(), -) { - val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - - if (isMiuix) { - MiuixIcon( - imageVector = imageVector, - contentDescription = contentDescription, - modifier = modifier, - tint = tint - ) - } else { - Icon( - imageVector = imageVector, - contentDescription = contentDescription, - modifier = modifier, - tint = tint - ) - } -} - -@Composable -fun currentContentColor(): Color { - val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - return if (isMiuix) { - MiuixLocalContentColor.current - } else { - MaterialLocalContentColor.current - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt index eb9eda5f4..f22b6a59b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt @@ -5,6 +5,7 @@ import androidx.compose.material3.BottomAppBarDefaults import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItemDefaults +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -12,7 +13,6 @@ 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 @@ -85,7 +85,7 @@ fun RowScope.AppNavigationBarItem( icon = m3Icon, colors = NavigationBarItemDefaults.colors(indicatorColor = m3IndicatorColor), label = if (m3ShowLabel) { - { AppText(labelString) } + { Text(labelString) } } else null, alwaysShowLabel = m3AlwaysShowLabel ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt new file mode 100644 index 000000000..956c90b46 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt @@ -0,0 +1,127 @@ +package io.legado.app.ui.widget.components + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.input.InputTransformation +import androidx.compose.foundation.text.input.KeyboardActionHandler +import androidx.compose.foundation.text.input.OutputTransformation +import androidx.compose.foundation.text.input.TextFieldLineLimits +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldColors +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.TextFieldLabelPosition +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.graphics.takeOrElse +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Density +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.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.TextField as MiuixTextField + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AppTextField( + state: TextFieldState, + modifier: Modifier = Modifier, + enabled: Boolean = true, + readOnly: Boolean = false, + // 1. 核心思想:保留 AppText 的统一样式与颜色降级参数 + textStyle: TextStyle? = null, + textColor: Color = Color.Unspecified, + // 2. 将 Label 统一定义为 String 以兼容两套引擎 + label: String? = null, + // 3. 保留 M3 TextField 的所有其他参数 + labelPosition: TextFieldLabelPosition = TextFieldLabelPosition.Attached(), + placeholder: @Composable (() -> Unit)? = null, + leadingIcon: @Composable (() -> Unit)? = null, + trailingIcon: @Composable (() -> Unit)? = null, + prefix: @Composable (() -> Unit)? = null, + suffix: @Composable (() -> Unit)? = null, + supportingText: @Composable (() -> Unit)? = null, + isError: Boolean = false, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + lineLimits: TextFieldLineLimits = TextFieldLineLimits.Default, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + scrollState: ScrollState = rememberScrollState(), + shape: Shape = TextFieldDefaults.shape, + colors: TextFieldColors = TextFieldDefaults.colors(), + contentPadding: PaddingValues? = null, + interactionSource: MutableInteractionSource? = null, +) { + val baseStyle = textStyle ?: LegadoTheme.typography.bodyMedium + val defaultTextColor = LegadoTheme.colorScheme.onSurface + val finalTextColor = textColor.takeOrElse { + baseStyle.color.takeOrElse { defaultTextColor } + } + val mergedTextStyle = baseStyle.merge(color = finalTextColor) + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + if (isMiuix) { + MiuixTextField( + state = state, + modifier = modifier, + enabled = enabled, + readOnly = readOnly, + textStyle = MiuixTheme.textStyles.main, + label = label ?: "", + leadingIcon = leadingIcon, + trailingIcon = trailingIcon, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + lineLimits = lineLimits, + onTextLayout = onTextLayout, + scrollState = scrollState, + interactionSource = interactionSource + ) + } else { + val resolvedContentPadding = + contentPadding ?: if (label == null || labelPosition is TextFieldLabelPosition.Above) { + TextFieldDefaults.contentPaddingWithoutLabel() + } else { + TextFieldDefaults.contentPaddingWithLabel() + } + TextField( + state = state, + modifier = modifier, + enabled = enabled, + readOnly = readOnly, + textStyle = mergedTextStyle, + labelPosition = labelPosition, + label = label?.let { { AppText(it) } }, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIcon = trailingIcon, + prefix = prefix, + suffix = suffix, + supportingText = supportingText, + isError = isError, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + lineLimits = lineLimits, + onTextLayout = onTextLayout, + scrollState = scrollState, + shape = shape, + colors = colors, + contentPadding = resolvedContentPadding, + interactionSource = interactionSource + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt b/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt index 66df4fb29..2659e0ee2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt @@ -24,6 +24,7 @@ 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 +import io.legado.app.ui.widget.components.text.AnimatedTextLine @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable diff --git a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt index 8d91e4feb..81ba5e057 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt @@ -1,12 +1,10 @@ package io.legado.app.ui.widget.components 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.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.input.rememberTextFieldState @@ -25,47 +23,36 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.SettingItem import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun GroupManageBottomSheet( + show: Boolean, groups: List, onDismissRequest: () -> Unit, onUpdateGroup: (oldGroup: String, newGroup: String) -> Unit, onDeleteGroup: (group: String) -> Unit ) { - GlassModalBottomSheet( - onDismissRequest = onDismissRequest + AppModalBottomSheet( + show = show, + onDismissRequest = onDismissRequest, + title = stringResource(R.string.group_manage), ) { - Column( - modifier = Modifier - .padding(horizontal = 16.dp) - .padding(bottom = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - AppText( - modifier = Modifier.padding(bottom = 16.dp), - text = stringResource(R.string.group_manage), - style = LegadoTheme.typography.titleMedium - ) - LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) { - items(groups, key = { it }) { group -> - GroupItem( - group = group, - onUpdateGroup = onUpdateGroup, - onDeleteGroup = onDeleteGroup - ) - } + LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) { + items(groups, key = { it }) { group -> + GroupItem( + group = group, + onUpdateGroup = onUpdateGroup, + onDeleteGroup = onDeleteGroup + ) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt b/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt index d62ac9726..7f2facbae 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt @@ -1,32 +1,14 @@ package io.legado.app.ui.widget.components -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.animateContentSize -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.scaleIn -import androidx.compose.animation.scaleOut -import androidx.compose.foundation.layout.Box -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.lazy.LazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.input.TextFieldLineLimits -import androidx.compose.foundation.text.input.clearText import androidx.compose.foundation.text.input.rememberTextFieldState -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Clear -import androidx.compose.material.icons.filled.Search -import androidx.compose.material.icons.filled.VerticalAlignTop -import androidx.compose.material3.DropdownMenu import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -37,14 +19,15 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.Alignment 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.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import io.legado.app.ui.widget.components.icon.AppIcon +import io.legado.app.ui.widget.components.icon.AppIcons import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -53,10 +36,10 @@ fun SearchBarSection( onQueryChange: (String) -> Unit, placeholder: String = "搜索...", leadingIcon: @Composable (() -> Unit)? = { - SmallIconButton( - icon = Icons.Default.Search, - contentDescription = null, - onClick = {}) + AppIcon( + imageVector = AppIcons.Search, + contentDescription = null + ) }, backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerLow, scrollState: LazyListState? = null, @@ -65,7 +48,6 @@ fun SearchBarSection( dropdownMenu: (@Composable (onDismiss: () -> Unit) -> Unit)? = null ) { var showMenu by remember { mutableStateOf(false) } - val textFieldState = rememberTextFieldState(initialText = query) LaunchedEffect(query) { @@ -91,79 +73,19 @@ fun SearchBarSection( } } - Surface( - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp, bottom = 4.dp), - shape = RoundedCornerShape(32.dp), - color = backgroundColor - ) { - TextField( + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + val searchTextField = @Composable { + AppTextField( state = textFieldState, modifier = Modifier .fillMaxWidth() - .heightIn(min = 48.dp) - .padding(horizontal = 4.dp), + .then( + if (isMiuix) Modifier.padding(horizontal = 16.dp, vertical = 8.dp) + else Modifier + ), placeholder = { AppText(placeholder) }, leadingIcon = leadingIcon, - trailingIcon = { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(end = 4.dp) - .animateContentSize() - ) { - - AnimatedVisibility( - visible = textFieldState.text.isNotEmpty(), - enter = fadeIn() + scaleIn(), - exit = fadeOut() + scaleOut() - ) { - SmallIconButton( - onClick = { textFieldState.clearText() }, - icon = Icons.Default.Clear, - contentDescription = "清空输入" - ) - } - - AnimatedVisibility( - visible = showScrollToTop, - enter = fadeIn() + scaleIn(), - exit = fadeOut() + scaleOut() - ) { - SmallIconButton( - onClick = { - scope.launch { - scrollState?.animateScrollToItem(0) - } - }, - icon = Icons.Default.VerticalAlignTop, - contentDescription = "回到顶部" - ) - } - - if (trailingIcon != null) { - Box { - IconButton( - onClick = { - if (dropdownMenu != null) showMenu = true - } - ) { - trailingIcon() - } - - if (dropdownMenu != null) { - DropdownMenu( - expanded = showMenu, - onDismissRequest = { showMenu = false } - ) { - dropdownMenu { showMenu = false } - } - } - } - } - } - }, lineLimits = TextFieldLineLimits.SingleLine, colors = TextFieldDefaults.colors( focusedContainerColor = Color.Transparent, @@ -171,13 +93,21 @@ fun SearchBarSection( disabledContainerColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, - ), - contentPadding = PaddingValues( - top = 4.dp, - bottom = 4.dp, - start = 12.dp, - end = 12.dp ) ) } + + if (isMiuix) { + searchTextField() + } else { + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, bottom = 4.dp), + shape = RoundedCornerShape(32.dp), + color = backgroundColor + ) { + searchTextField() + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt b/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt new file mode 100644 index 000000000..3f0ca7038 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt @@ -0,0 +1,52 @@ +package io.legado.app.ui.widget.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Remove +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.widget.components.button.SmallOutlinedIconButton +import io.legado.app.ui.widget.components.card.TextCard + +@Composable +fun ValueStepper( + value: Float, + displayValue: Float, + valueRange: ClosedFloatingPointRange, + onValueChange: (Float) -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + SmallOutlinedIconButton( + onClick = { + val newValue = (value.toInt() - 1).toFloat().coerceIn(valueRange) + onValueChange(newValue) + }, + icon = Icons.Default.Remove + ) + TextCard( + cornerRadius = 8.dp, + horizontalPadding = 8.dp, + verticalPadding = 4.dp, + text = displayValue.toInt().toString(), + backgroundColor = LegadoTheme.colorScheme.surfaceContainer, + contentColor = LegadoTheme.colorScheme.onSurface + ) + SmallOutlinedIconButton( + onClick = { + val newValue = (value.toInt() + 1).toFloat().coerceIn(valueRange) + onValueChange(newValue) + }, + icon = Icons.Default.Add + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt index 832f97f4a..d436c0ca8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt @@ -7,13 +7,10 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.padding import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -25,13 +22,15 @@ 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.button.PrimaryButton +import io.legado.app.ui.widget.components.button.SecondaryButton +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun BookmarkEditSheet( + show: Boolean, bookmark: Bookmark, onDismiss: () -> Unit, onSave: (Bookmark) -> Unit, @@ -42,21 +41,16 @@ fun BookmarkEditSheet( var bookText by remember { mutableStateOf(bookmark.bookText) } var content by remember { mutableStateOf(bookmark.content) } - GlassModalBottomSheet( - onDismissRequest = onDismiss + AppModalBottomSheet( + show = show, + onDismissRequest = onDismiss, + title = bookmark.chapterName, ) { Column( modifier = Modifier .fillMaxWidth() - .padding(16.dp) .navigationBarsPadding() ) { - AppText( - text = bookmark.chapterName, - style = LegadoTheme.typography.titleMedium, - modifier = Modifier.padding(bottom = 16.dp) - ) - OutlinedTextField( value = bookText, onValueChange = { bookText = it }, @@ -82,15 +76,13 @@ fun BookmarkEditSheet( horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically ) { - OutlinedButton( + SecondaryButton( onClick = { showDeleteConfirmDialog = true }, - colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.error), - modifier = Modifier.weight(1f) - ) { - AppText("删除") - } + modifier = Modifier.weight(1f), + text = "删除" + ) - Button( + PrimaryButton( onClick = { val newBookmark = bookmark.apply { this.bookText = bookText @@ -98,10 +90,9 @@ fun BookmarkEditSheet( } onSave(newBookmark) }, - modifier = Modifier.weight(1f) - ) { - AppText("保存") - } + modifier = Modifier.weight(1f), + text = "保存" + ) } Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt index cab80e10f..470d44a1c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -31,7 +30,7 @@ fun BookmarkItem( onLongClick: () -> Unit ) { val backgroundColor by animateColorAsState( - targetValue = if (isDur) MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.3f) + targetValue = if (isDur) LegadoTheme.colorScheme.secondaryContainer.copy(alpha = 0.3f) else Color.Transparent, label = "BgColor" ) @@ -53,7 +52,7 @@ fun BookmarkItem( AppText( text = bookmark.chapterName, style = LegadoTheme.typography.titleSmallEmphasized, - color = if (isDur) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary + color = if (isDur) LegadoTheme.colorScheme.primary else LegadoTheme.colorScheme.secondary ) if (bookmark.bookText.isNotEmpty()) { @@ -63,7 +62,7 @@ fun BookmarkItem( style = LegadoTheme.typography.bodyMedium, maxLines = 2, overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.onSurfaceVariant + color = LegadoTheme.colorScheme.onSurfaceVariant ) } @@ -72,7 +71,7 @@ fun BookmarkItem( AppText( text = bookmark.content, style = LegadoTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.primary + color = LegadoTheme.colorScheme.primary ) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/AppButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/AppButton.kt new file mode 100644 index 000000000..5595c43ff --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/AppButton.kt @@ -0,0 +1,74 @@ +package io.legado.app.ui.widget.components.button + +import androidx.compose.material3.Button +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import io.legado.app.ui.theme.LegadoTheme.composeEngine +import io.legado.app.ui.theme.ThemeResolver +import top.yukonga.miuix.kmp.basic.Button as MiuixButton +import top.yukonga.miuix.kmp.basic.ButtonDefaults as MiuixButtonDefaults +import top.yukonga.miuix.kmp.basic.Text as MiuixText + +@Composable +fun PrimaryButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + text: String +) { + if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + colors = MiuixButtonDefaults.buttonColorsPrimary() + ) { + MiuixText( + text = text + ) + } + } else { + Button( + onClick = onClick, + modifier = modifier, + enabled = enabled, + ) { + Text( + text = text, + ) + } + } +} + +@Composable +fun SecondaryButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + text: String +) { + if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + colors = MiuixButtonDefaults.buttonColors() + ) { + MiuixText( + text = text + ) + } + } else { + OutlinedButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + ) { + Text( + text = text + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/AppIconButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/AppIconButton.kt new file mode 100644 index 000000000..c14bceaa3 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/AppIconButton.kt @@ -0,0 +1,61 @@ +package io.legado.app.ui.widget.components.button + +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonColors +import androidx.compose.material3.IconButtonDefaults +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.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import top.yukonga.miuix.kmp.basic.IconButton as MiuixIconButton +import top.yukonga.miuix.kmp.basic.IconButtonDefaults as MiuixIconButtonDefaults + +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun AppIconButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + interactionSource: MutableInteractionSource? = null, + //M3 + colors: IconButtonColors = IconButtonDefaults.iconButtonColors(), + shape: Shape = IconButtonDefaults.standardShape, + // MIUIX + holdDownState: Boolean = false, + miuixBackgroundColor: Color = Color.Unspecified, + miuixCornerRadius: Dp? = null, + miuixMinHeight: Dp? = null, + miuixMinWidth: Dp? = null, + content: @Composable () -> Unit +) { + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + if (isMiuix) { + MiuixIconButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + holdDownState = holdDownState, + backgroundColor = miuixBackgroundColor, + cornerRadius = MiuixIconButtonDefaults.CornerRadius, + minHeight = MiuixIconButtonDefaults.MinHeight, + minWidth = MiuixIconButtonDefaults.MinWidth, + content = content + ) + } else { + IconButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + colors = colors, + interactionSource = interactionSource, + shape = shape, + content = content + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixButton.kt similarity index 92% rename from app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt rename to app/src/main/java/io/legado/app/ui/widget/components/button/MiuixButton.kt index 27093ad7e..3fa9c73dd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixButton.kt @@ -7,21 +7,21 @@ 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 +import top.yukonga.miuix.kmp.basic.IconButton as MiuixIconButton @Composable -fun MiuixButton( +fun MiuixIconButton( modifier: Modifier = Modifier, imageVector: ImageVector = MiuixIcons.Regular.Back, tint: Color = LocalContentColor.current, contentDescription: String? = stringResource(id = R.string.back), onClick: () -> Unit, ) { - IconButton( + MiuixIconButton( onClick = onClick, modifier = modifier ) { @@ -44,7 +44,7 @@ fun MiuixToggleButton( uncheckedTint: Color = LocalContentColor.current, contentDescription: String? = null, ) { - IconButton( + MiuixIconButton( onClick = { onCheckedChange(!checked) }, modifier = modifier ) { diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt index 6d1a51ad0..6bd6ffc96 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.widget.components.button import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -80,8 +82,24 @@ fun SmallIconButton( fun SmallOutlinedIconButton( onClick: () -> Unit, icon: ImageVector, + modifier: Modifier = Modifier, contentDescription: String? = null ) { + + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + if (isMiuix) { + MiuixIconButton( + onClick = onClick, + modifier = modifier.size(32.dp), + backgroundColor = LegadoTheme.colorScheme.surfaceContainer + ) { + MiuixIcon( + imageVector = icon, + contentDescription = contentDescription, + modifier = Modifier.size(18.dp) + ) + } + } else { CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { OutlinedIconButton( onClick = onClick, @@ -102,6 +120,7 @@ fun SmallOutlinedIconButton( ) } } + } } @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -109,27 +128,42 @@ fun SmallOutlinedIconButton( fun SmallTonalIconButton( onClick: () -> Unit, icon: ImageVector, + modifier: Modifier = Modifier, contentDescription: String? = null ) { - CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { - FilledTonalIconButton( + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + + if (isMiuix) { + MiuixIconButton( onClick = onClick, - modifier = Modifier.size( - IconButtonDefaults.extraSmallContainerSize( - IconButtonDefaults.IconButtonWidthOption.Uniform - ) - ), - shapes = IconButtonDefaults.shapes(), - colors = IconButtonDefaults.filledTonalIconButtonColors() + modifier = modifier.size(32.dp), + backgroundColor = LegadoTheme.colorScheme.surfaceContainer ) { - Icon( + MiuixIcon( imageVector = icon, contentDescription = contentDescription, - modifier = Modifier.size( - IconButtonDefaults.extraSmallIconSize - ) + modifier = Modifier.size(18.dp) ) } + } else { + CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { + FilledTonalIconButton( + onClick = onClick, + modifier = modifier.size( + IconButtonDefaults.extraSmallContainerSize( + IconButtonDefaults.IconButtonWidthOption.Uniform + ) + ), + shapes = IconButtonDefaults.shapes(), + colors = IconButtonDefaults.filledTonalIconButtonColors() + ) { + Icon( + imageVector = icon, + contentDescription = contentDescription, + modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize) + ) + } + } } } @@ -142,35 +176,67 @@ fun SmallOutlinedIconToggleButton( modifier: Modifier = Modifier, contentDescription: String? = null ) { - val defaultShape = IconButtonDefaults.extraSmallRoundShape - val pressedShape = IconButtonDefaults.extraSmallPressedShape - val checkedShape = IconButtonDefaults.extraSmallSelectedRoundShape + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - val toggleShapes = remember(defaultShape, checkedShape) { - IconToggleButtonShapes( - shape = defaultShape, - pressedShape = pressedShape, - checkedShape = checkedShape + if (isMiuix) { + + val containerColor by animateColorAsState( + targetValue = if (checked) LegadoTheme.colorScheme.primaryContainer else LegadoTheme.colorScheme.surfaceContainer, + animationSpec = tween(150), + label = "MiuixToggleContainerColor" ) - } - CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { - OutlinedIconToggleButton( - checked = checked, - onCheckedChange = onCheckedChange, - modifier = modifier.size( - IconButtonDefaults.extraSmallContainerSize( - IconButtonDefaults.IconButtonWidthOption.Uniform - ) - ), - shapes = toggleShapes + val iconTint by animateColorAsState( + targetValue = if (checked) LegadoTheme.colorScheme.onPrimaryContainer else LegadoTheme.colorScheme.onSurfaceVariant, + animationSpec = tween(150), + label = "MiuixToggleIconTint" + ) + + MiuixIconButton( + onClick = { onCheckedChange(!checked) }, + modifier = modifier + .size(32.dp), + backgroundColor = containerColor ) { - Icon( + MiuixIcon( imageVector = icon, contentDescription = contentDescription, - modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize), + tint = iconTint, + modifier = Modifier.size(18.dp) ) } + + } else { + val defaultShape = IconButtonDefaults.extraSmallRoundShape + val pressedShape = IconButtonDefaults.extraSmallPressedShape + val checkedShape = IconButtonDefaults.extraSmallSelectedRoundShape + + val toggleShapes = remember(defaultShape, checkedShape) { + IconToggleButtonShapes( + shape = defaultShape, + pressedShape = pressedShape, + checkedShape = checkedShape + ) + } + + CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { + OutlinedIconToggleButton( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier.size( + IconButtonDefaults.extraSmallContainerSize( + IconButtonDefaults.IconButtonWidthOption.Uniform + ) + ), + shapes = toggleShapes + ) { + Icon( + imageVector = icon, + contentDescription = contentDescription, + modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize), + ) + } + } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt index 4dc24e991..9c3d49600 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt @@ -12,7 +12,12 @@ 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 top.yukonga.miuix.kmp.basic.Button as MiuixButton +import top.yukonga.miuix.kmp.basic.ButtonDefaults as MiuixButtonDefaults +import top.yukonga.miuix.kmp.basic.Text as MiuixText @Composable fun SmallTextButton( @@ -21,21 +26,33 @@ fun SmallTextButton( modifier: Modifier = Modifier, onClick: () -> Unit ) { - TextButton( - onClick = onClick, - modifier = modifier, - contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), - shape = MaterialTheme.shapes.small - ) { - Icon( - imageVector = icon, - contentDescription = null, - modifier = Modifier.size(16.dp) - ) - Spacer(Modifier.width(4.dp)) - AppText( - text = text, - style = LegadoTheme.typography.labelMedium - ) + if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixButton( + onClick = onClick, + modifier = modifier, + colors = MiuixButtonDefaults.buttonColors() + ) { + MiuixText( + text = text + ) + } + } else { + TextButton( + onClick = onClick, + modifier = modifier, + contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), + shape = MaterialTheme.shapes.small + ) { + Icon( + imageVector = icon, + contentDescription = null, + modifier = Modifier.size(16.dp) + ) + Spacer(Modifier.width(4.dp)) + AppText( + text = text, + style = LegadoTheme.typography.labelMedium + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt index f6251874d..22edae070 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt @@ -36,6 +36,7 @@ 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 io.legado.app.ui.widget.components.icon.AppIcons import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults import kotlinx.coroutines.delay @@ -107,12 +108,12 @@ fun TopBarButton( fun TopbarNavigationButton( onClick: () -> Unit, modifier: Modifier = Modifier, - imageVector: ImageVector = Icons.AutoMirrored.Filled.ArrowBack, + imageVector: ImageVector = AppIcons.Back, contentDescription: String? = "返回", style: TopBarButtonVariant = TopBarButtonVariant.Filled ) { if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) { - MiuixButton( + MiuixIconButton( onClick = onClick, imageVector = imageVector, contentDescription = contentDescription, @@ -138,7 +139,7 @@ fun TopBarActionButton( ) { val enableProgressive = ThemeConfig.enableProgressiveBlur if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) { - MiuixButton( + MiuixIconButton( onClick = onClick, imageVector = imageVector, contentDescription = contentDescription, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt index f8db95733..221416e7f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt @@ -86,7 +86,6 @@ fun SelectionItemCard( GlassCard( onClick = onToggleSelection, modifier = modifier - .padding(horizontal = 16.dp) .fillMaxWidth(), shape = MaterialTheme.shapes.medium, containerColor = animatedContainerColor, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt index c548ce905..1e0f55646 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -17,11 +16,8 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp 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.AnimatedTextLine -import io.legado.app.ui.widget.components.AppIcon -import top.yukonga.miuix.kmp.theme.MiuixTheme +import io.legado.app.ui.widget.components.icon.AppIcon +import io.legado.app.ui.widget.components.text.AnimatedTextLine @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -40,17 +36,8 @@ fun TextCard( spacing: Dp = 4.dp, textStyle: TextStyle = LegadoTheme.typography.labelSmallEmphasized ) { - val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - - val defaultBackground = if (isMiuix) - MiuixTheme.colorScheme.surfaceContainer - else - MaterialTheme.colorScheme.primaryContainer - - val defaultContent = if (isMiuix) - MiuixTheme.colorScheme.onSurface - else - MaterialTheme.colorScheme.primary + val defaultBackground = LegadoTheme.colorScheme.surfaceContainer + val defaultContent = LegadoTheme.colorScheme.onSurface val finalBackgroundColor = backgroundColor ?: defaultBackground val finalContentColor = contentColor ?: defaultContent diff --git a/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt b/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt index ec7f0be47..dc452a334 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt @@ -7,17 +7,13 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Update import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable 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( @@ -31,16 +27,6 @@ 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, @@ -58,8 +44,6 @@ fun BookshelfCover( modifier = Modifier .align(Alignment.TopEnd) .padding(2.dp), - backgroundColor = backgroundColor, - contentColor = contentColor, cornerRadius = 4.dp, horizontalPadding = 4.dp, verticalPadding = 0.dp diff --git a/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt index 26390c39c..76bae95ae 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt @@ -41,12 +41,13 @@ 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun ColorPickerSheet( + show: Boolean, initialColor: Int, onDismissRequest: () -> Unit, onColorSelected: (Int) -> Unit @@ -80,7 +81,7 @@ fun ColorPickerSheet( ) } - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet(show = show, onDismissRequest = onDismissRequest) { Column( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt index f97428813..cd4cff794 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -14,26 +13,39 @@ 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.theme.ThemeResolver +import top.yukonga.miuix.kmp.theme.MiuixTheme @Composable fun PillDivider( modifier: Modifier = Modifier, thickness: Dp = 2.dp, widthFraction: Float = 0.2f, - color: Color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.6f) + color: Color = LegadoTheme.colorScheme.outlineVariant.copy(alpha = 0.6f) ) { - Box( - modifier = modifier - .fillMaxWidth() - .padding(vertical = 4.dp), - contentAlignment = Alignment.Center - ) { + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + if (isMiuix) { Box( modifier = Modifier - .fillMaxWidth(widthFraction) - .height(thickness) - .clip(CircleShape) - .background(color) + .fillMaxWidth() + .height(4.dp) + .background(MiuixTheme.colorScheme.secondaryContainer) ) + } else { + Box( + modifier = modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .fillMaxWidth(widthFraction) + .height(thickness) + .clip(CircleShape) + .background(color) + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt index e189ed31c..d1d81729d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth 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.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -24,8 +23,8 @@ fun PillHeaderDivider( title: String, modifier: Modifier = Modifier, dotSize: Dp = 2.dp, - dotColor: Color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.8f), - titleColor: Color = MaterialTheme.colorScheme.primary + dotColor: Color = LegadoTheme.colorScheme.outlineVariant.copy(alpha = 0.8f), + titleColor: Color = LegadoTheme.colorScheme.primary ) { Row( modifier = modifier diff --git a/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt index 0ed751d4d..bdd0c3b8a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.InsertDriveFile @@ -17,7 +16,6 @@ import androidx.compose.material.icons.filled.CloudUpload import androidx.compose.material.icons.filled.EditNote import androidx.compose.material.icons.filled.FolderOpen import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -28,7 +26,8 @@ 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.icon.AppIcon +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText enum class FilePickerSheetMode { @@ -38,6 +37,7 @@ enum class FilePickerSheetMode { @OptIn(ExperimentalMaterial3Api::class) @Composable fun FilePickerSheet( + show: Boolean, onDismissRequest: () -> Unit, title: String = stringResource(R.string.select_operation), onSelectSysDir: (() -> Unit)? = null, @@ -47,22 +47,17 @@ fun FilePickerSheet( onUpload: (() -> Unit)? = null, allowExtensions: Array? = null, ) { - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, + title = title, onDismissRequest = onDismissRequest, - containerColor = { it.surface } + containerColor = LegadoTheme.colorScheme.surface ) { Column( modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 8.dp), + .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { - AppText( - text = title, - style = LegadoTheme.typography.titleMedium, - modifier = Modifier.padding(bottom = 20.dp) - ) - FlowRow( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp), @@ -127,7 +122,7 @@ private fun RowScope.FilePickerOptionCard( .weight(1f) .height(100.dp), shape = MaterialTheme.shapes.medium, - color = MaterialTheme.colorScheme.surfaceContainerLow, + color = LegadoTheme.colorScheme.surfaceContainerLow, tonalElevation = 2.dp ) { Column( @@ -135,11 +130,11 @@ private fun RowScope.FilePickerOptionCard( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - Icon( + AppIcon( imageVector = icon, contentDescription = null, modifier = Modifier.size(32.dp), - tint = MaterialTheme.colorScheme.primary + tint = LegadoTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(8.dp)) AppText( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt new file mode 100644 index 000000000..f8c8361fd --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt @@ -0,0 +1,88 @@ +package io.legado.app.ui.widget.components.icon + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.paint +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.geometry.isUnspecified +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.takeOrElse +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp +import io.legado.app.ui.theme.LegadoTheme + +/** + * 1. 基础 AppIcon 实现 + */ +@Composable +fun AppIcon( + painter: Painter, + contentDescription: String?, + modifier: Modifier = Modifier, + tint: Color = Color.Unspecified, +) { + val defaultTintColor = LegadoTheme.colorScheme.onSurface + val finalTint = tint.takeOrElse { defaultTintColor } + + val colorFilter = remember(finalTint) { + if (finalTint == Color.Unspecified) null else ColorFilter.tint(finalTint) + } + + val semantics = if (contentDescription != null) { + Modifier.semantics { + this.contentDescription = contentDescription + this.role = Role.Image + } + } else { + Modifier + } + + Box( + modifier + .defaultIconSize(painter) + .paint(painter, colorFilter = colorFilter, contentScale = ContentScale.Fit) + .then(semantics) + ) +} + +@Composable +fun AppIcon( + imageVector: ImageVector?, + contentDescription: String?, + modifier: Modifier = Modifier, + tint: Color = Color.Unspecified, +) { + if (imageVector == null) return + + AppIcon( + painter = rememberVectorPainter(imageVector), + contentDescription = contentDescription, + modifier = modifier, + tint = tint, + ) +} + +/** + * 3. 辅助扩展函数:处理图标的默认尺寸 + * M3 和 MIUIX 内部都有 defaultSizeFor,如果 painter 没有固有尺寸,默认设为 24.dp + */ +private fun Modifier.defaultIconSize(painter: Painter): Modifier { + return this.then( + if (painter.intrinsicSize == Size.Unspecified || painter.intrinsicSize.isUnspecified) { + Modifier.size(24.dp) + } else { + Modifier + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt new file mode 100644 index 000000000..df274d7fd --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt @@ -0,0 +1,54 @@ +package io.legado.app.ui.widget.components.icon + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Clear +import androidx.compose.material.icons.filled.Replay +import androidx.compose.material.icons.filled.Search +import androidx.compose.runtime.Composable +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.icon.MiuixIcons +import top.yukonga.miuix.kmp.icon.basic.Search +import top.yukonga.miuix.kmp.icon.extended.Back +import top.yukonga.miuix.kmp.icon.extended.Close +import top.yukonga.miuix.kmp.icon.extended.Refresh + +/** + * 应用全局图标映射层 + */ +object AppIcons { + + private val isMiuix: Boolean + @Composable + get() = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + val Search: ImageVector + @Composable + get() = if (isMiuix) { + MiuixIcons.Basic.Search + } else { + Icons.Default.Search + } + + val Close: ImageVector + @Composable + get() = if (isMiuix) { + MiuixIcons.Close + } else { + Icons.Default.Clear + } + + val Back: ImageVector + @Composable + get() = if (isMiuix) { + MiuixIcons.Back + } else { + Icons.AutoMirrored.Filled.ArrowBack + } + + val Replay: ImageVector + @Composable + get() = if (isMiuix) MiuixIcons.Refresh ?: Icons.Default.Replay else Icons.Default.Replay +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt b/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt index 2c72a0c8e..e62220280 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt @@ -1,10 +1,6 @@ package io.legado.app.ui.widget.components.importComponents import android.annotation.SuppressLint -import androidx.compose.animation.animateColorAsState -import androidx.compose.animation.animateContentSize -import androidx.compose.animation.core.FastOutSlowInEasing -import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -26,16 +22,10 @@ import androidx.compose.material.icons.filled.SelectAll import androidx.compose.material3.AlertDialog import androidx.compose.material3.AssistChip import androidx.compose.material3.Button -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField @@ -44,7 +34,6 @@ import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -59,9 +48,11 @@ 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.button.SmallIconButton +import io.legado.app.ui.widget.components.card.SelectionItemCard +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet +import io.legado.app.ui.widget.components.text.AnimatedText import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch @@ -116,31 +107,42 @@ fun SourceInputDialog( ) } +//TODO: 动画 @SuppressLint("ConfigurationScreenWidthHeight") @OptIn(ExperimentalMaterial3Api::class) @Composable fun BatchImportDialog( title: String, - importState: BaseImportUiState.Success, + importState: BaseImportUiState, onDismissRequest: () -> Unit, - onConfirm: (List) -> Unit, // 返回选中的原始数据列表 + onConfirm: (List) -> Unit, onToggleItem: (index: Int) -> Unit, onToggleAll: (isSelected: Boolean) -> Unit, onItemInfoClick: (index: Int) -> Unit = {}, - // 插槽:允许调用方自定义顶部菜单 topBarActions: @Composable RowScope.() -> Unit = {}, - // 插槽:自定义每一行的显示内容 - itemContent: @Composable (data: T, status: ImportStatus) -> Unit + itemTitle: (data: T) -> String, + itemSubtitle: (data: T) -> String? = { null } ) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val show = importState is BaseImportUiState.Success + + var cachedState by remember { mutableStateOf?>(null) } + if (importState is BaseImportUiState.Success) { + cachedState = importState + } + + if (!show && cachedState == null) return + val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } - val selectedCount = importState.items.count { it.isSelected } - val totalCount = importState.items.size - GlassModalBottomSheet( + val currentState = cachedState!! + val selectedCount = currentState.items.count { it.isSelected } + val totalCount = currentState.items.size + + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest, - containerColor = { it.surfaceContainer } + containerColor = LegadoTheme.colorScheme.surfaceContainer ) { AppScaffold( modifier = Modifier @@ -171,44 +173,34 @@ fun BatchImportDialog( ImportBottomBar( selectedCount = selectedCount, totalCount = totalCount, - onToggleSelectAll = { isAll -> onToggleAll(isAll) }, + onToggleSelectAll = onToggleAll, onConfirm = { - scope.launch { sheetState.hide() }.invokeOnCompletion { - if (!sheetState.isVisible) { - val selectedData = - importState.items.filter { it.isSelected }.map { it.data } - onConfirm(selectedData) - } - } + val selectedData = + currentState.items.filter { it.isSelected }.map { it.data } + onConfirm(selectedData) }, - onCancel = { - scope.launch { sheetState.hide() }.invokeOnCompletion { - if (!sheetState.isVisible) { - onDismissRequest() - } - } - } + onCancel = onDismissRequest ) } ) { padding -> LazyColumn( - modifier = Modifier - .padding(padding), + modifier = Modifier.padding(padding), contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - itemsIndexed(importState.items, key = { _, item -> item.data.hashCode() }) { index, itemWrapper -> + itemsIndexed( + currentState.items, + key = { _, item -> item.data.hashCode() }) { index, itemWrapper -> ImportItemRow( + title = itemTitle(itemWrapper.data), + subtitle = itemSubtitle(itemWrapper.data), isSelected = itemWrapper.isSelected, status = itemWrapper.status, onClick = { onToggleItem(index) }, onInfoClick = { - scope.launch { - snackbarHostState.showSnackbar("其实还没写桀桀桀") - } + scope.launch { snackbarHostState.showSnackbar("其实还没写桀桀桀") } onItemInfoClick(index) - }, - content = { itemContent(itemWrapper.data, itemWrapper.status) } + } ) } } @@ -216,74 +208,47 @@ fun BatchImportDialog( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable -private fun ImportItemRow( +fun ImportItemRow( + title: String, + subtitle: String? = null, isSelected: Boolean, status: ImportStatus, onClick: () -> Unit, - onInfoClick: () -> Unit, - content: @Composable () -> Unit + onInfoClick: () -> Unit ) { - val containerColor by animateColorAsState( - targetValue = if (isSelected) - MaterialTheme.colorScheme.secondaryContainer - else - MaterialTheme.colorScheme.surface, - animationSpec = tween( - durationMillis = 200, - easing = FastOutSlowInEasing - ), - label = "CardColor" - ) - - Card( - onClick = onClick, - modifier = Modifier.fillMaxWidth(), - shape = MaterialTheme.shapes.medium, - colors = CardDefaults.cardColors( - containerColor = containerColor - ) - ) { - ListItem( - modifier = Modifier.animateContentSize(), - headlineContent = { content() }, - leadingContent = { - Checkbox( - checked = isSelected, - onCheckedChange = null - ) - }, - supportingContent = { - AppText( - text = when (status) { - ImportStatus.New -> "新增" - ImportStatus.Update -> "更新" - ImportStatus.Existing -> "已有" - ImportStatus.Error -> "错误" - }, - style = LegadoTheme.typography.labelMedium, - color = when (status) { - ImportStatus.New -> MaterialTheme.colorScheme.primary - ImportStatus.Update -> MaterialTheme.colorScheme.secondary - ImportStatus.Error -> MaterialTheme.colorScheme.error - else -> MaterialTheme.colorScheme.outline - } - ) - }, - trailingContent = { - IconButton(onClick = onInfoClick) { - Icon( - imageVector = Icons.Default.Info, - contentDescription = "详情" - ) - } - }, - colors = ListItemDefaults.colors( - containerColor = Color.Transparent + SelectionItemCard( + title = title, + subtitle = subtitle, + isSelected = isSelected, + inSelectionMode = true, + onToggleSelection = onClick, + modifier = Modifier.padding(vertical = 4.dp), + trailingAction = { + AppText( + text = when (status) { + ImportStatus.New -> "新增" + ImportStatus.Update -> "更新" + ImportStatus.Existing -> "已有" + ImportStatus.Error -> "错误" + }, + style = LegadoTheme.typography.labelMedium, + color = when (status) { + ImportStatus.New -> MaterialTheme.colorScheme.primary + ImportStatus.Update -> MaterialTheme.colorScheme.secondary + ImportStatus.Error -> MaterialTheme.colorScheme.error + else -> MaterialTheme.colorScheme.outline + }, + modifier = Modifier.padding(end = 4.dp) ) - ) - } + + SmallIconButton( + onClick = onInfoClick, + icon = Icons.Default.Info, + contentDescription = "详情" + ) + } + ) } @OptIn(ExperimentalMaterial3ExpressiveApi::class) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt b/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt index a9d75e7b3..c26987158 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.util.fastFirstOrNull import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastLastOrNull import androidx.compose.ui.util.fastMaxBy +import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.lazylist.Scroller.STICKY_HEADER_KEY_PREFIX import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow @@ -67,7 +68,7 @@ fun VerticalFastScroller( listState: LazyListState, modifier: Modifier = Modifier, thumbAllowed: () -> Boolean = { true }, - thumbColor: Color = MaterialTheme.colorScheme.primary, + thumbColor: Color = LegadoTheme.colorScheme.primary, topContentPadding: Dp = Dp.Hairline, bottomContentPadding: Dp = Dp.Hairline, endContentPadding: Dp = Dp.Hairline, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt index 033191122..cbb74cc93 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt @@ -3,6 +3,8 @@ package io.legado.app.ui.widget.components.menuItem import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.material3.DropdownMenu import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialExpressiveTheme @@ -15,8 +17,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.Dp 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.theme.rememberOpaqueColorScheme - +import top.yukonga.miuix.kmp.basic.ListPopupColumn +import top.yukonga.miuix.kmp.extra.SuperListPopup @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable @@ -24,31 +29,50 @@ fun RoundDropdownMenu( expanded: Boolean, onDismissRequest: () -> Unit, modifier: Modifier = Modifier, + // M3 专属视觉参数,Miuix 模式下会优雅降级(忽略) shape: Shape = MaterialTheme.shapes.medium, shadowElevation: Dp = 4.dp, verticalSpacing: Dp = 8.dp, content: @Composable ColumnScope.(dismiss: () -> Unit) -> Unit ) { - val colorScheme = rememberOpaqueColorScheme() + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) - DropdownMenu( - expanded = expanded, - onDismissRequest = onDismissRequest, - modifier = modifier, - shape = shape, - shadowElevation = shadowElevation, - containerColor = colorScheme.surfaceContainerLow - ) { - MaterialExpressiveTheme( - colorScheme = colorScheme, - typography = Typography(), - motionScheme = MotionScheme.expressive(), - shapes = Shapes() + if (isMiuix) { + SuperListPopup( + show = expanded, + onDismissRequest = onDismissRequest, + popupModifier = modifier ) { - Column( - verticalArrangement = Arrangement.spacedBy(verticalSpacing) + ListPopupColumn { + Column() { + Spacer(Modifier.height(12.dp)) + content(onDismissRequest) + Spacer(Modifier.height(12.dp)) + } + } + } + } else { + val colorScheme = rememberOpaqueColorScheme() + + DropdownMenu( + expanded = expanded, + onDismissRequest = onDismissRequest, + modifier = modifier, + shape = shape, + shadowElevation = shadowElevation, + containerColor = colorScheme.surfaceContainerLow + ) { + MaterialExpressiveTheme( + colorScheme = colorScheme, + typography = Typography(), + motionScheme = MotionScheme.expressive(), + shapes = Shapes() ) { - content(onDismissRequest) + Column( + verticalArrangement = Arrangement.spacedBy(verticalSpacing) + ) { + content(onDismissRequest) + } } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt index 8e20a0531..437baaf81 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.widget.components.menuItem +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -11,54 +13,114 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn -import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight 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.theme.rememberOpaqueColorScheme +import io.legado.app.ui.widget.components.icon.AppIcon +import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.Text as MiuixText @Composable fun RoundDropdownMenuItem( - text: @Composable () -> Unit, + text: String, + color: Color = LegadoTheme.colorScheme.surface, onClick: () -> Unit, modifier: Modifier = Modifier, + isSelected: Boolean = false, leadingIcon: @Composable (() -> Unit)? = null, trailingIcon: @Composable (() -> Unit)? = null, enabled: Boolean = true, contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding, interactionSource: MutableInteractionSource? = null, ) { - val colorScheme = rememberOpaqueColorScheme() + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) val interaction = interactionSource ?: remember { MutableInteractionSource() } - val contentColor = - if (enabled) MaterialTheme.colorScheme.onSurface - else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) + if (isMiuix) { + val backgroundColor = if (isSelected) { + LegadoTheme.colorScheme.primaryContainer + } else { + Color.Transparent + } - Surface( - onClick = onClick, - modifier = modifier - .padding(horizontal = 8.dp) - .fillMaxWidth(), - enabled = enabled, - shape = MaterialTheme.shapes.small, - color = colorScheme.surface, - interactionSource = interaction - ) { - CompositionLocalProvider( - LocalContentColor provides contentColor, - LocalTextStyle provides LegadoTheme.typography.labelLarge + val contentColor = if (isSelected) { + LegadoTheme.colorScheme.onPrimaryContainer + } else { + LegadoTheme.colorScheme.onSurface + } + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + modifier = modifier + .fillMaxWidth() + .drawBehind { drawRect(backgroundColor) } + .clickable( + interactionSource = interaction, + indication = androidx.compose.foundation.LocalIndication.current, + enabled = enabled, + onClick = onClick + ) + .padding(horizontal = 20.dp, vertical = 12.dp) + ) { + CompositionLocalProvider( + LocalContentColor provides contentColor, + LocalTextStyle provides MiuixTheme.textStyles.body1 + ) { + if (leadingIcon != null) { + leadingIcon() + Spacer(Modifier.width(12.dp)) + } + + Box( + modifier = Modifier.weight(1f), + contentAlignment = Alignment.CenterStart + ) { + MiuixText( + text = text, + fontWeight = FontWeight.Medium + ) + } + + if (trailingIcon != null) { + Spacer(Modifier.width(12.dp)) + trailingIcon() + } + } + } + } else { + val colorScheme = rememberOpaqueColorScheme() + val contentColor = if (enabled) { + MaterialTheme.colorScheme.onSurface + } else { + MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) + } + + Surface( + onClick = onClick, + modifier = modifier + .padding(horizontal = 8.dp) + .fillMaxWidth(), + enabled = enabled, + shape = MaterialTheme.shapes.small, + color = colorScheme.surface, + interactionSource = interaction ) { Row( modifier = Modifier @@ -67,17 +129,20 @@ fun RoundDropdownMenuItem( .widthIn(min = 120.dp), verticalAlignment = Alignment.CenterVertically ) { - if (leadingIcon != null) { leadingIcon() - Spacer(Modifier.width(8.dp)) + Spacer(Modifier.width(12.dp)) } Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.CenterStart ) { - text() + Text( + modifier = Modifier.widthIn(max = 200.dp), + text = text, + style = LegadoTheme.typography.bodyMediumEmphasized + ) } if (trailingIcon != null) { @@ -94,9 +159,9 @@ fun MenuItemIcon( imageVector: ImageVector, modifier: Modifier = Modifier, contentDescription: String? = null, - tint: Color = LocalContentColor.current + tint: Color = Color.Unspecified ) { - Icon( + AppIcon( imageVector = imageVector, contentDescription = contentDescription, modifier = modifier.size(18.dp), diff --git a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt new file mode 100644 index 000000000..b1b678f7e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt @@ -0,0 +1,138 @@ +package io.legado.app.ui.widget.components.modalBottomSheet + +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.BottomSheetDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MaterialExpressiveTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.MotionScheme +import androidx.compose.material3.Shapes +import androidx.compose.material3.Text +import androidx.compose.material3.Typography +import androidx.compose.material3.rememberModalBottomSheetState +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.platform.LocalDensity +import androidx.compose.ui.platform.LocalWindowInfo +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.DpSize +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.theme.rememberOpaqueColorScheme +import top.yukonga.miuix.kmp.extra.WindowBottomSheet + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun AppModalBottomSheet( + show: Boolean, + onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, + title: String? = null, + startAction: @Composable (() -> Unit)? = null, + endAction: @Composable (() -> Unit)? = null, + containerColor: Color = LegadoTheme.colorScheme.surfaceContainerLow, + content: @Composable ColumnScope.() -> Unit +) { + if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) { + WindowBottomSheet( + show = show, + modifier = modifier, + title = title, + startAction = startAction, + endAction = endAction, + insideMargin = DpSize(16.dp, 12.dp), + backgroundColor = containerColor, + onDismissRequest = onDismissRequest, + onDismissFinished = onDismissRequest, + enableWindowDim = true, + allowDismiss = true + ) { + Column( + modifier = Modifier.fillMaxWidth(), + content = content + ) + } + } else { + if (show) { + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val colorScheme = rememberOpaqueColorScheme() + val density = LocalDensity.current + val maxHeight = with(density) { + LocalWindowInfo.current.containerSize.height.toDp() * 0.8f + } + + ModalBottomSheet( + onDismissRequest = onDismissRequest, + sheetState = sheetState, + containerColor = containerColor, + contentColor = colorScheme.onSurface, + dragHandle = { BottomSheetDefaults.DragHandle() } + ) { + MaterialExpressiveTheme( + colorScheme = colorScheme, + typography = Typography(), + motionScheme = MotionScheme.expressive(), + shapes = Shapes() + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .heightIn(max = maxHeight) + .animateContentSize() + .then(modifier) + ) { + val hasHeader = + !title.isNullOrEmpty() || startAction != null || endAction != null + + if (hasHeader) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp), + contentAlignment = Alignment.Center + ) { + if (startAction != null) { + Box(modifier = Modifier.align(Alignment.CenterStart)) { + startAction() + } + } + + if (!title.isNullOrEmpty()) { + Text( + text = title, + style = LegadoTheme.typography.titleMediumEmphasized, + color = colorScheme.onSurface, + textAlign = TextAlign.Center, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.padding(horizontal = 56.dp) + ) + } + + if (endAction != null) { + Box(modifier = Modifier.align(Alignment.CenterEnd)) { + endAction() + } + } + } + } + + content() + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/GlassModalBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/GlassModalBottomSheet.kt deleted file mode 100644 index 187cb8b30..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/GlassModalBottomSheet.kt +++ /dev/null @@ -1,64 +0,0 @@ -package io.legado.app.ui.widget.components.modalBottomSheet - -import androidx.compose.animation.animateContentSize -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn -import androidx.compose.material3.ColorScheme -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.MaterialExpressiveTheme -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.MotionScheme -import androidx.compose.material3.Shapes -import androidx.compose.material3.SheetState -import androidx.compose.material3.Typography -import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalWindowInfo -import io.legado.app.ui.theme.rememberOpaqueColorScheme - -@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) -@Composable -fun GlassModalBottomSheet( - onDismissRequest: () -> Unit, - modifier: Modifier = Modifier, - sheetState: SheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true - ), - containerColor: (ColorScheme) -> Color = { it.surfaceContainerLow }, - content: @Composable ColumnScope.() -> Unit -) { - val colorScheme = rememberOpaqueColorScheme() - val density = LocalDensity.current - val maxHeight = with(density) { - LocalWindowInfo.current.containerSize.height.toDp() * 0.8f - } - - ModalBottomSheet( - onDismissRequest = onDismissRequest, - sheetState = sheetState, - containerColor = containerColor(colorScheme), - contentColor = colorScheme.onSurface - ) { - MaterialExpressiveTheme( - colorScheme = colorScheme, - typography = Typography(), - motionScheme = MotionScheme.expressive(), - shapes = Shapes() - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .heightIn(max = maxHeight) - .animateContentSize() - .then(modifier), - content = content - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt index e2cb8063a..ae07cccf4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt @@ -35,7 +35,7 @@ import androidx.compose.ui.graphics.Color 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.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch @@ -52,6 +52,7 @@ data class RuleEditFields( @OptIn(ExperimentalMaterial3Api::class) @Composable fun RuleEditSheet( + show: Boolean, rule: T?, title: String, label1: String, @@ -74,7 +75,8 @@ fun RuleEditSheet( fun getCurrentEntity() = fromFields(RuleEditFields(name, rule1, rule2), rule) - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Box(modifier = Modifier.fillMaxWidth()) { diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt index e5e83b6f6..4934919f7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt @@ -1,13 +1,12 @@ package io.legado.app.ui.widget.components.settingItem -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.filled.Remove import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -20,17 +19,22 @@ import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp -import io.legado.app.ui.widget.components.button.SmallOutlinedIconButton +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.ValueStepper 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 +import top.yukonga.miuix.kmp.basic.BasicComponent +import top.yukonga.miuix.kmp.extra.SuperSwitch +import top.yukonga.miuix.kmp.extra.WindowDropdown +import top.yukonga.miuix.kmp.basic.Slider as MiuixSlider @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable @@ -41,49 +45,73 @@ fun CompactDropdownSettingItem( entryValues: Array, description: String? = null, imageVector: ImageVector? = null, - color: Color? = MaterialTheme.colorScheme.surface, + color: Color? = LegadoTheme.colorScheme.surface, shape: Shape = MaterialTheme.shapes.small, onValueChange: (String) -> Unit ) { - val currentEntry = displayEntries.getOrNull(entryValues.indexOf(selectedValue)) ?: selectedValue + if (ThemeResolver.isMiuixEngine(composeEngine)) { + val selectedIndex = entryValues.indexOf(selectedValue).coerceAtLeast(0) + val spinnerItems = displayEntries.toList() - SettingItem( - title = title, - description = description, - imageVector = imageVector, - color = color, - shape = shape, - trailingContent = { - TextCard( - cornerRadius = 8.dp, - horizontalPadding = 8.dp, - verticalPadding = 4.dp, - text = currentEntry, - backgroundColor = MaterialTheme.colorScheme.surfaceContainer, - contentColor = MaterialTheme.colorScheme.onSurface - ) - }, - 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 - ) + WindowDropdown( + 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, + imageVector = imageVector, + color = color, + shape = shape, + trailingContent = { + TextCard( + cornerRadius = 8.dp, + horizontalPadding = 8.dp, + verticalPadding = 4.dp, + text = currentEntry, + backgroundColor = MaterialTheme.colorScheme.surfaceContainer, + contentColor = MaterialTheme.colorScheme.onSurface + ) + }, + dropdownMenu = { onDismiss -> + displayEntries.forEachIndexed { index, display -> + RoundDropdownMenuItem( + 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 + ) + } + } + ) + } } @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -104,59 +132,78 @@ fun CompactSliderSettingItem( var sliderValue by remember(value) { mutableFloatStateOf(value) } var displayValue by remember(value) { mutableFloatStateOf(value) } - SettingItem( - title = title, - description = description, - imageVector = imageVector, - color = color, - shape = shape, - expanded = expanded, - onExpandChange = { expanded = it }, - trailingContent = { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - SmallOutlinedIconButton( - onClick = { - val newValue = (value.toInt() - 1).toFloat().coerceIn(valueRange) - onValueChange(newValue) - }, - icon = Icons.Default.Remove + if (ThemeResolver.isMiuixEngine(composeEngine)) { + Column(modifier = Modifier.fillMaxWidth()) { + BasicComponent( + title = title, + summary = description, + onClick = { expanded = !expanded }, + endActions = { + ValueStepper( + value = value, + displayValue = displayValue, + valueRange = valueRange, + onValueChange = onValueChange + ) + } + ) + + AnimatedVisibility(visible = expanded) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + MiuixSlider( + value = sliderValue, + onValueChange = { + sliderValue = it + displayValue = it + }, + onValueChangeFinished = { + onValueChange(sliderValue) + }, + valueRange = valueRange, + steps = steps, + modifier = Modifier.fillMaxWidth() + ) + } + } + } + } else { + SettingItem( + title = title, + description = description, + imageVector = imageVector, + color = color, + shape = shape, + expanded = expanded, + onExpandChange = { expanded = it }, + trailingContent = { + ValueStepper( + value = value, + displayValue = displayValue, + valueRange = valueRange, + onValueChange = onValueChange ) - TextCard( - cornerRadius = 8.dp, - horizontalPadding = 8.dp, - verticalPadding = 4.dp, - text = displayValue.toInt().toString(), - backgroundColor = MaterialTheme.colorScheme.surfaceContainer, - contentColor = MaterialTheme.colorScheme.onSurface - ) - SmallOutlinedIconButton( - onClick = { - val newValue = (value.toInt() + 1).toFloat().coerceIn(valueRange) - onValueChange(newValue) + }, + expandContent = { + Slider( + value = sliderValue, + onValueChange = { + sliderValue = it + displayValue = it }, - icon = Icons.Default.Add + onValueChangeFinished = { + onValueChange(sliderValue) + }, + valueRange = valueRange, + steps = steps, + modifier = Modifier.fillMaxWidth() ) } - }, - expandContent = { - Slider( - value = sliderValue, - onValueChange = { - sliderValue = it - displayValue = it - }, - onValueChangeFinished = { - onValueChange(sliderValue) - }, - valueRange = valueRange, - steps = steps, - modifier = Modifier.fillMaxWidth() - ) - } - ) + ) + } LaunchedEffect(value) { if (!expanded) { @@ -177,20 +224,30 @@ fun CompactSwitchSettingItem( enabled: Boolean = true, onCheckedChange: (Boolean) -> Unit ) { - SettingItem( - title = title, - description = description, - imageVector = imageVector, - color = color, - shape = shape, - onClick = { if (enabled) onCheckedChange(!checked) }, - trailingContent = { - Switch( - modifier = Modifier.scale(0.8f), - checked = checked, - onCheckedChange = onCheckedChange, - enabled = enabled - ) - } - ) + if (ThemeResolver.isMiuixEngine(composeEngine)) { + SuperSwitch( + title = title, + summary = description, + checked = checked, + onCheckedChange = onCheckedChange, + enabled = enabled, + ) + } else { + SettingItem( + title = title, + description = description, + imageVector = imageVector, + color = color, + shape = shape, + onClick = { if (enabled) onCheckedChange(!checked) }, + trailingContent = { + Switch( + modifier = Modifier.scale(0.8f), + checked = checked, + onCheckedChange = onCheckedChange, + enabled = enabled + ) + } + ) + } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt index 532302557..f6db6cc20 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt @@ -11,7 +11,6 @@ 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 @@ -64,7 +63,7 @@ fun DropdownListSettingItem( dropdownMenu = { onDismiss -> displayEntries.forEachIndexed { index, display -> RoundDropdownMenuItem( - text = { AppText(display) }, + text = display, onClick = { onValueChange(entryValues[index]) onDismiss() diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt index f0e458f20..e9263a254 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt @@ -6,8 +6,7 @@ import androidx.compose.ui.graphics.vector.ImageVector 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 +import top.yukonga.miuix.kmp.extra.SuperSwitch @Composable @@ -23,22 +22,12 @@ fun SwitchSettingItem( val composeEngine = LegadoTheme.composeEngine if (ThemeResolver.isMiuixEngine(composeEngine)) { - val toggleAction = { - if (enabled) onCheckedChange(!checked) - } - - BasicComponent( + SuperSwitch( title = title, summary = description, + checked = checked, + onCheckedChange = onCheckedChange, enabled = enabled, - onClick = toggleAction, - endActions = { - Switch( - checked = checked, - onCheckedChange = onCheckedChange, - enabled = enabled - ) - } ) } else { SettingItem( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt b/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AppTabRow.kt similarity index 95% rename from app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt rename to app/src/main/java/io/legado/app/ui/widget/components/tabRow/AppTabRow.kt index c9afdf567..a1cc3085d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AppTabRow.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.Tab +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -11,12 +12,11 @@ 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( +fun AppTabRow( tabTitles: List, selectedTabIndex: Int, onTabSelected: (Int) -> Unit, @@ -48,7 +48,7 @@ fun AdaptiveTabRow( selected = selectedTabIndex == index, onClick = { onTabSelected(index) }, text = { - AppText( + Text( text = title, maxLines = 1, overflow = TextOverflow.Ellipsis, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt b/app/src/main/java/io/legado/app/ui/widget/components/text/AnimatedText.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt rename to app/src/main/java/io/legado/app/ui/widget/components/text/AnimatedText.kt index cfa21f308..ac075d549 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/text/AnimatedText.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.widget.components +package io.legado.app.ui.widget.components.text import androidx.compose.animation.AnimatedContent import androidx.compose.animation.fadeIn @@ -22,7 +22,6 @@ 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( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt b/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt index 51a1735e5..0826f1579 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt @@ -1,11 +1,11 @@ package io.legado.app.ui.widget.components.text -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.Text +import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextStyle @@ -16,10 +16,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.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 +import io.legado.app.ui.theme.LegadoTheme @Composable fun AppText( @@ -41,53 +38,41 @@ fun AppText( onTextLayout: ((TextLayoutResult) -> Unit)? = null, style: TextStyle? = null, ) { + val baseStyle = style ?: LegadoTheme.typography.bodyMedium - 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 - ) + // 2. 获取默认文本色:直接拿你自己封装的 LegadoTheme.colorScheme.onSurface + val defaultTextColor = LegadoTheme.colorScheme.onSurface + + // 3. 颜色降级逻辑:传入的 color -> style 中的 color -> 主题默认色 + val finalTextColor = color.takeOrElse { + baseStyle.color.takeOrElse { defaultTextColor } } + + BasicText( + text = text, + modifier = modifier, + style = baseStyle.merge( + color = finalTextColor, + fontSize = fontSize, + fontWeight = fontWeight, + textAlign = textAlign ?: TextAlign.Unspecified, + lineHeight = lineHeight, + fontFamily = fontFamily, + textDecoration = textDecoration, + fontStyle = fontStyle, + letterSpacing = letterSpacing, + ), + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines + ) } @Composable fun AppText( - text: AnnotatedString, + text: AnnotatedString, // 接收 AnnotatedString modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, @@ -105,46 +90,36 @@ fun AppText( onTextLayout: ((TextLayoutResult) -> Unit)? = null, style: TextStyle? = null, ) { + // 1. 获取基础样式:如果外部没传 style,直接拿你自己封装的 LegadoTheme.typography.bodyMedium + // 这完美避开了 M3 的 LocalTextStyle,且自动适配 Miuix/M3 引擎! + val baseStyle = style ?: LegadoTheme.typography.bodyMedium - 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 - ) + // 2. 获取默认文本色:直接拿你自己封装的 LegadoTheme.colorScheme.onSurface + val defaultTextColor = LegadoTheme.colorScheme.onSurface + + // 3. 颜色降级逻辑:传入的 color -> style 中的 color -> 主题默认色 + val finalTextColor = color.takeOrElse { + baseStyle.color.takeOrElse { defaultTextColor } } + + BasicText( + text = text, + modifier = modifier, + style = baseStyle.merge( + color = finalTextColor, + fontSize = fontSize, + fontWeight = fontWeight, + textAlign = textAlign ?: TextAlign.Unspecified, + lineHeight = lineHeight, + fontFamily = fontFamily, + textDecoration = textDecoration, + fontStyle = fontStyle, + letterSpacing = letterSpacing, + ), + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines + ) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt index b88003858..9cbd6c4fc 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt @@ -10,12 +10,9 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -23,12 +20,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import io.legado.app.ui.widget.components.AnimatedTextLine import io.legado.app.ui.widget.components.SearchBarSection import io.legado.app.ui.widget.components.button.TopBarActionButton import io.legado.app.ui.widget.components.button.TopbarNavigationButton +import io.legado.app.ui.widget.components.icon.AppIcons import io.legado.app.ui.widget.components.list.ListUiState import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu +import io.legado.app.ui.widget.components.text.AnimatedTextLine @OptIn(ExperimentalMaterial3Api::class) @@ -70,7 +68,7 @@ fun DynamicTopAppBar( if (isSelecting || onBackClick != null) { TopbarNavigationButton( onClick = { if (isSelecting) onClearSelection() else onBackClick?.invoke() }, - imageVector = if (isSelecting) Icons.Default.Close else Icons.AutoMirrored.Filled.ArrowBack, + imageVector = if (isSelecting) AppIcons.Close else AppIcons.Back, contentDescription = if (isSelecting) "取消选择" else "返回" ) } @@ -113,7 +111,6 @@ fun DynamicTopAppBar( query = state.searchKey, onQueryChange = onSearchQueryChange, placeholder = searchPlaceholder, - leadingIcon = { Icon(searchLeadingIcon, null) }, trailingIcon = searchTrailingIcon, dropdownMenu = searchDropdownMenu ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt index 0a1cee57e..118d14a5c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt @@ -21,8 +21,8 @@ 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.responsiveHazeEffect -import io.legado.app.ui.widget.components.AdaptiveAnimatedText import io.legado.app.ui.widget.components.GlassDefaults +import io.legado.app.ui.widget.components.text.AdaptiveAnimatedText import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.basic.TopAppBar as MiuixTopAppBar