初始版本

This commit is contained in:
HapeLee
2026-03-30 12:28:46 +08:00
parent f31138338b
commit 01fb34a1bd
106 changed files with 2889 additions and 1524 deletions
+5
View File
@@ -286,4 +286,9 @@ dependencies {
implementation(libs.material.kolor) implementation(libs.material.kolor)
implementation(libs.haze.core) implementation(libs.haze.core)
implementation(libs.haze.materials) implementation(libs.haze.materials)
implementation(libs.miuix)
implementation(libs.miuix.icons)
implementation(libs.capsule)
implementation(libs.backdrop)
implementation(libs.timber)
} }
@@ -82,6 +82,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -113,6 +114,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -141,6 +143,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -169,6 +172,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -202,6 +206,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -236,6 +241,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -265,6 +271,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -293,6 +300,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -321,6 +329,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -350,6 +359,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -378,6 +388,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -406,6 +417,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -434,6 +446,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -462,6 +475,7 @@ interface BookDao {
durChapterPos, durChapterPos,
latestChapterTitle, latestChapterTitle,
latestChapterTime, latestChapterTime,
lastCheckCount,
totalChapterNum, totalChapterNum,
durChapterIndex, durChapterIndex,
type, type,
@@ -15,9 +15,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -31,13 +29,15 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppConst.appInfo 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.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.SplicedColumnGroup
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.card.TextCard
import io.legado.app.ui.widget.components.settingItem.SettingItem 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) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -59,7 +59,7 @@ fun AboutScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { Text(stringResource(R.string.about)) }, title = stringResource(R.string.about),
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBack) TopbarNavigationButton(onClick = onBack)
}, },
@@ -81,9 +81,9 @@ fun AboutScreen(
.width(160.dp) .width(160.dp)
.align(Alignment.CenterHorizontally) .align(Alignment.CenterHorizontally)
) )
Text( AppText(
text = stringResource(R.string.app_name), text = stringResource(R.string.app_name),
style = MaterialTheme.typography.bodyLarge, style = LegadoTheme.typography.bodyLarge,
fontSize = 18.sp, fontSize = 18.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier modifier = Modifier
@@ -98,9 +98,9 @@ fun AboutScreen(
.fillMaxWidth() .fillMaxWidth()
.wrapContentWidth(Alignment.CenterHorizontally) .wrapContentWidth(Alignment.CenterHorizontally)
.padding(vertical = 4.dp)) .padding(vertical = 4.dp))
Text( AppText(
text = stringResource(R.string.about_description), text = stringResource(R.string.about_description),
style = MaterialTheme.typography.bodyLarge, style = LegadoTheme.typography.bodyLarge,
fontSize = 12.sp, fontSize = 12.sp,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -18,7 +18,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -31,7 +30,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppLog 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.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.utils.LogUtils import io.legado.app.utils.LogUtils
import java.util.Date import java.util.Date
@@ -52,9 +53,9 @@ fun AppLogSheet(
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text( AppText(
text = stringResource(R.string.log), text = stringResource(R.string.log),
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
IconButton(onClick = { IconButton(onClick = {
@@ -82,17 +83,17 @@ fun AppLogSheet(
showStackTrace?.let { stackTrace -> showStackTrace?.let { stackTrace ->
AlertDialog( AlertDialog(
onDismissRequest = { showStackTrace = null }, onDismissRequest = { showStackTrace = null },
title = { Text("Log") }, title = { AppText("Log") },
text = { text = {
SelectionContainer { SelectionContainer {
Column(modifier = Modifier.verticalScroll(rememberScrollState())) { Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
Text(text = stackTrace, style = MaterialTheme.typography.bodySmall) AppText(text = stackTrace, style = LegadoTheme.typography.bodySmall)
} }
} }
}, },
confirmButton = { confirmButton = {
TextButton(onClick = { showStackTrace = null }) { 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) .clickable(onClick = onClick)
.padding(16.dp) .padding(16.dp)
) { ) {
Text( AppText(
text = LogUtils.logTimeFormat.format(Date(item.first)), text = LogUtils.logTimeFormat.format(Date(item.first)),
style = MaterialTheme.typography.labelMedium, style = LegadoTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.outline color = MaterialTheme.colorScheme.outline
) )
Text( AppText(
text = item.second, text = item.second,
style = MaterialTheme.typography.bodyMedium, style = LegadoTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 4.dp) modifier = Modifier.padding(top = 4.dp)
) )
} }
@@ -26,7 +26,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue 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.CollapsibleHeader
import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.AppScaffold
import io.legado.app.ui.widget.components.EmptyMessageView 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.SearchBarSection
import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet
import io.legado.app.ui.widget.components.bookmark.BookmarkItem 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.lazylist.Scroller
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu 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.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 import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class, @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
@@ -98,11 +98,7 @@ fun AllBookmarkScreen(
topBar = { topBar = {
Column { Column {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { title = "所有书签",
Text(
text = "所有书签"
)
},
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBack) TopbarNavigationButton(onClick = onBack)
@@ -132,7 +128,7 @@ fun AllBookmarkScreen(
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("导出 JSON") }, text = { AppText("导出 JSON") },
onClick = { onClick = {
showMenu = false showMenu = false
pendingExportIsMd = false pendingExportIsMd = false
@@ -140,7 +136,7 @@ fun AllBookmarkScreen(
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("导出 Markdown") }, text = { AppText("导出 Markdown") },
onClick = { onClick = {
showMenu = false showMenu = false
pendingExportIsMd = true pendingExportIsMd = true
@@ -52,7 +52,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState 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.SearchBook
import io.legado.app.data.entities.rule.ExploreKind import io.legado.app.data.entities.rule.ExploreKind
import io.legado.app.model.BookShelfState 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.responsiveHazeEffect
import io.legado.app.ui.theme.responsiveHazeSource 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.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.SearchBarSection
import io.legado.app.ui.widget.components.button.AnimatedTextButton import io.legado.app.ui.widget.components.button.AnimatedTextButton
import io.legado.app.ui.widget.components.button.TopBarActionButton 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.RoundDropdownMenu
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem 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.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.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -194,16 +194,16 @@ fun ExploreShowScreen(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
) { ) {
Text( AppText(
text = "布局列数", text = "布局列数",
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold) style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold)
) )
Spacer(modifier = Modifier.width(12.dp)) Spacer(modifier = Modifier.width(12.dp))
TextCard( TextCard(
text = "$gridColumnCount", text = "$gridColumnCount",
textStyle = MaterialTheme.typography.titleSmall, textStyle = LegadoTheme.typography.titleSmall,
verticalPadding = 4.dp, verticalPadding = 4.dp,
horizontalPadding = 12.dp, horizontalPadding = 12.dp,
cornerRadius = 12.dp cornerRadius = 12.dp
@@ -229,7 +229,7 @@ fun ExploreShowScreen(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
) { ) {
Text("完成") AppText("完成")
} }
} }
} }
@@ -294,13 +294,7 @@ fun ExploreShowScreen(
modifier = Modifier.responsiveHazeEffect( modifier = Modifier.responsiveHazeEffect(
state = hazeState state = hazeState
), ),
title = { title = selectedTitle ?: title,
AnimatedTextLine(
selectedTitle ?: title,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
colors = GlassTopAppBarDefaults.glassColors(), colors = GlassTopAppBarDefaults.glassColors(),
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBack) TopbarNavigationButton(onClick = onBack)
@@ -346,7 +340,7 @@ fun ExploreShowScreen(
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("全部显示") }, text = { AppText("全部显示") },
onClick = { onClick = {
viewModel.setFilterState(BookFilterState.SHOW_ALL) viewModel.setFilterState(BookFilterState.SHOW_ALL)
showMenu = false showMenu = false
@@ -358,7 +352,7 @@ fun ExploreShowScreen(
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("隐藏已在书架的同源书籍") }, text = { AppText("隐藏已在书架的同源书籍") },
onClick = { onClick = {
viewModel.setFilterState(BookFilterState.HIDE_IN_SHELF) viewModel.setFilterState(BookFilterState.HIDE_IN_SHELF)
showMenu = false showMenu = false
@@ -370,7 +364,7 @@ fun ExploreShowScreen(
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("隐藏已在书架的非同源书籍") }, text = { AppText("隐藏已在书架的非同源书籍") },
onClick = { onClick = {
viewModel.setFilterState(BookFilterState.HIDE_SAME_NAME_AUTHOR) viewModel.setFilterState(BookFilterState.HIDE_SAME_NAME_AUTHOR)
showMenu = false showMenu = false
@@ -382,7 +376,7 @@ fun ExploreShowScreen(
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("只显示不在书架的书籍") }, text = { AppText("只显示不在书架的书籍") },
onClick = { onClick = {
viewModel.setFilterState(BookFilterState.SHOW_NOT_IN_SHELF_ONLY) viewModel.setFilterState(BookFilterState.SHOW_NOT_IN_SHELF_ONLY)
showMenu = false showMenu = false
@@ -509,7 +503,7 @@ fun KindGridItem(
enabled = isClickable, enabled = isClickable,
selected = isSelected, selected = isSelected,
label = { label = {
Text( AppText(
text = kind.title, text = kind.title,
fontSize = 12.sp, fontSize = 12.sp,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -576,32 +570,32 @@ fun ExploreBookItem(
.weight(1f) .weight(1f)
.align(Alignment.CenterVertically)) { .align(Alignment.CenterVertically)) {
Text( AppText(
text = book.name, text = book.name,
style = MaterialTheme.typography.titleSmall, style = LegadoTheme.typography.titleSmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
Row { Row {
Text( AppText(
text = book.author, text = book.author,
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
maxLines = 1 maxLines = 1
) )
val latestChapter = book.latestChapterTitle val latestChapter = book.latestChapterTitle
if (!latestChapter.isNullOrEmpty()) { if (!latestChapter.isNullOrEmpty()) {
Text( AppText(
text = "", text = "",
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = Color.Gray, color = Color.Gray,
maxLines = 1 maxLines = 1
) )
Text( AppText(
text = "最新: $latestChapter", text = "最新: $latestChapter",
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
@@ -612,9 +606,9 @@ fun ExploreBookItem(
val intro = book.intro?.replace("\\s+".toRegex(), "") ?: "" val intro = book.intro?.replace("\\s+".toRegex(), "") ?: ""
if (intro.isNotEmpty()) { if (intro.isNotEmpty()) {
Text( AppText(
text = intro, text = intro,
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
color = Color.Gray, color = Color.Gray,
maxLines = 2, maxLines = 2,
minLines = 2, minLines = 2,
@@ -654,9 +648,12 @@ fun ExploreBookGridItem(
val content: (@Composable RowScope.() -> Unit)? = if (!badgeText.isNullOrBlank()) { val content: (@Composable RowScope.() -> Unit)? = if (!badgeText.isNullOrBlank()) {
{ {
Text( AppText(
text = badgeText, 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 { } else {
@@ -681,9 +678,9 @@ fun ExploreBookGridItem(
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text( AppText(
text = book.name, text = book.name,
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
maxLines = 2, maxLines = 2,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
@@ -698,10 +695,10 @@ fun TagChip(text: String) {
color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.5f), color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.5f),
shape = RoundedCornerShape(4.dp) shape = RoundedCornerShape(4.dp)
) { ) {
Text( AppText(
text = text, text = text,
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp), modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
} }
@@ -742,13 +739,13 @@ fun LoadMoreFooter(
}, },
label = "FooterTextChange" label = "FooterTextChange"
) { text -> ) { text ->
Text( AppText(
text = text, text = text,
color = when { color = when {
errorMsg != null -> Color.Red errorMsg != null -> Color.Red
else -> Color.Gray else -> Color.Gray
}, },
style = MaterialTheme.typography.bodySmall style = LegadoTheme.typography.bodySmall
) )
} }
@@ -18,11 +18,9 @@ import androidx.compose.material.icons.filled.Restore
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedIconButton import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
@@ -38,10 +36,12 @@ import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.data.entities.BookGroup import io.legado.app.data.entities.BookGroup
import io.legado.app.lib.dialogs.alert 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.cover.Cover
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet 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.CompactDropdownSettingItem
import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem 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.FileUtils
import io.legado.app.utils.MD5Utils import io.legado.app.utils.MD5Utils
import io.legado.app.utils.SelectImageContract import io.legado.app.utils.SelectImageContract
@@ -113,9 +113,9 @@ fun GroupEditContent(
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text( AppText(
text = stringResource(R.string.group_edit), text = stringResource(R.string.group_edit),
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
modifier = Modifier.padding(vertical = 16.dp) modifier = Modifier.padding(vertical = 16.dp)
) )
@@ -138,7 +138,7 @@ fun GroupEditContent(
OutlinedTextField( OutlinedTextField(
value = groupName, value = groupName,
onValueChange = { groupName = it }, onValueChange = { groupName = it },
label = { Text(stringResource(R.string.group_name)) }, label = { AppText(stringResource(R.string.group_name)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
singleLine = true singleLine = true
) )
@@ -206,7 +206,7 @@ fun GroupEditContent(
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedButton(onClick = onDismissRequest) { OutlinedButton(onClick = onDismissRequest) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
Button(onClick = { Button(onClick = {
if (groupName.isEmpty()) { if (groupName.isEmpty()) {
@@ -235,7 +235,7 @@ fun GroupEditContent(
} }
} }
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
} }
} }
@@ -51,7 +51,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState 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.data.entities.Server
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.model.remote.RemoteBook 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.ActionItem
import io.legado.app.ui.widget.components.EmptyMessageView import io.legado.app.ui.widget.components.EmptyMessageView
import io.legado.app.ui.widget.components.SelectionActions 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.list.ListScaffold
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem 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.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.utils.ArchiveUtils import io.legado.app.utils.ArchiveUtils
import io.legado.app.utils.ConvertUtils import io.legado.app.utils.ConvertUtils
import io.legado.app.utils.FileDoc import io.legado.app.utils.FileDoc
@@ -157,19 +158,19 @@ fun RemoteBookScreen(
is RemoteBookDialog.DownloadArchive -> { is RemoteBookDialog.DownloadArchive -> {
AlertDialog( AlertDialog(
onDismissRequest = { dialogState = null }, onDismissRequest = { dialogState = null },
title = { Text(stringResource(R.string.draw)) }, title = { AppText(stringResource(R.string.draw)) },
text = { Text(stringResource(R.string.archive_not_found)) }, text = { AppText(stringResource(R.string.archive_not_found)) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = { OutlinedButton(onClick = {
scope.launch { viewModel.addToBookshelf(setOf(state.remoteBook)) } scope.launch { viewModel.addToBookshelf(setOf(state.remoteBook)) }
dialogState = null dialogState = null
}) { }) {
Text(stringResource(android.R.string.ok)) AppText(stringResource(android.R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { dialogState = null }) { 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 -> { is RemoteBookDialog.ReImport -> {
AlertDialog( AlertDialog(
onDismissRequest = { dialogState = null }, onDismissRequest = { dialogState = null },
title = { Text("是否重新加入书架?") }, title = { AppText("是否重新加入书架?") },
text = { Text("将会覆盖书籍") }, text = { AppText("将会覆盖书籍") },
confirmButton = { confirmButton = {
OutlinedButton(onClick = { OutlinedButton(onClick = {
scope.launch { viewModel.addToBookshelf(setOf(state.remoteBook)) } scope.launch { viewModel.addToBookshelf(setOf(state.remoteBook)) }
dialogState = null dialogState = null
}) { }) {
Text(stringResource(android.R.string.ok)) AppText(stringResource(android.R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { dialogState = null }) { TextButton(onClick = { dialogState = null }) {
Text(stringResource(android.R.string.cancel)) AppText(stringResource(android.R.string.cancel))
} }
} }
) )
@@ -259,7 +260,7 @@ fun RemoteBookScreen(
}, },
dropDownMenuContent = { dismiss -> dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("按名称排序") }, text = { AppText("按名称排序") },
onClick = { onClick = {
viewModel.toggleSort(RemoteBookSort.Name) viewModel.toggleSort(RemoteBookSort.Name)
dismiss() dismiss()
@@ -271,7 +272,7 @@ fun RemoteBookScreen(
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("按时间排序") }, text = { AppText("按时间排序") },
onClick = { onClick = {
viewModel.toggleSort(RemoteBookSort.Default) viewModel.toggleSort(RemoteBookSort.Default)
dismiss() dismiss()
@@ -381,9 +382,9 @@ private fun ServersSheetContent(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ) {
Text( AppText(
text = stringResource(R.string.server_config), text = stringResource(R.string.server_config),
style = MaterialTheme.typography.titleLarge style = LegadoTheme.typography.titleLarge
) )
IconButton(onClick = onAdd) { IconButton(onClick = onAdd) {
Icon(Icons.Default.Add, contentDescription = "添加") Icon(Icons.Default.Add, contentDescription = "添加")
@@ -447,9 +448,9 @@ private fun ServerItem(
ListItem( ListItem(
modifier = Modifier.animateContentSize(), modifier = Modifier.animateContentSize(),
headlineContent = { headlineContent = {
Text( AppText(
text = name, text = name,
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
@@ -462,9 +463,9 @@ private fun ServerItem(
}, },
supportingContent = url?.let { supportingContent = url?.let {
{ {
Text( AppText(
text = it, text = it,
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
@@ -514,16 +515,16 @@ private fun ServerConfigSheetContent(
.padding(16.dp) .padding(16.dp)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
Text( AppText(
text = if (server == null) "添加服务器" else "编辑服务器", text = if (server == null) "添加服务器" else "编辑服务器",
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
modifier = Modifier.padding(bottom = 16.dp) modifier = Modifier.padding(bottom = 16.dp)
) )
OutlinedTextField( OutlinedTextField(
value = name, value = name,
onValueChange = { name = it }, onValueChange = { name = it },
label = { Text("名称") }, label = { AppText("名称") },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
singleLine = true singleLine = true
) )
@@ -531,7 +532,7 @@ private fun ServerConfigSheetContent(
OutlinedTextField( OutlinedTextField(
value = url, value = url,
onValueChange = { url = it }, onValueChange = { url = it },
label = { Text("URL") }, label = { AppText("URL") },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
singleLine = true singleLine = true
) )
@@ -539,7 +540,7 @@ private fun ServerConfigSheetContent(
OutlinedTextField( OutlinedTextField(
value = username, value = username,
onValueChange = { username = it }, onValueChange = { username = it },
label = { Text("用户名") }, label = { AppText("用户名") },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
singleLine = true singleLine = true
) )
@@ -547,7 +548,7 @@ private fun ServerConfigSheetContent(
OutlinedTextField( OutlinedTextField(
value = password, value = password,
onValueChange = { password = it }, onValueChange = { password = it },
label = { Text("密码") }, label = { AppText("密码") },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
singleLine = true, singleLine = true,
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
@@ -571,7 +572,7 @@ private fun ServerConfigSheetContent(
onClick = onCancel, onClick = onCancel,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) { ) {
Text(stringResource(android.R.string.cancel)) AppText(stringResource(android.R.string.cancel))
} }
Button( Button(
onClick = { onClick = {
@@ -587,7 +588,7 @@ private fun ServerConfigSheetContent(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
enabled = name.isNotBlank() && url.isNotBlank() enabled = name.isNotBlank() && url.isNotBlank()
) { ) {
Text("保存") AppText("保存")
} }
} }
} }
@@ -625,9 +626,9 @@ private fun PathNavigationBar(
itemsIndexed(pathNames) { index, name -> itemsIndexed(pathNames) { index, name ->
val isLast = index == pathNames.lastIndex val isLast = index == pathNames.lastIndex
Text( AppText(
text = name, text = name,
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
fontWeight = if (isLast) FontWeight.SemiBold else FontWeight.Medium, fontWeight = if (isLast) FontWeight.SemiBold else FontWeight.Medium,
color = if (isLast) color = if (isLast)
MaterialTheme.colorScheme.primary MaterialTheme.colorScheme.primary
@@ -716,9 +717,9 @@ private fun RemoteBookItem(
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) { ) {
Text( AppText(
text = book.filename.substringBeforeLast("."), text = book.filename.substringBeforeLast("."),
style = MaterialTheme.typography.bodyMedium, style = LegadoTheme.typography.bodyMedium,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
@@ -732,7 +733,7 @@ private fun RemoteBookItem(
if (book.contentType.isNotEmpty()) { if (book.contentType.isNotEmpty()) {
TextCard( TextCard(
text = book.contentType.uppercase(), text = book.contentType.uppercase(),
textStyle = MaterialTheme.typography.labelSmall, textStyle = LegadoTheme.typography.labelSmall,
horizontalPadding = 4.dp, horizontalPadding = 4.dp,
verticalPadding = 2.dp, verticalPadding = 2.dp,
cornerRadius = 4.dp, cornerRadius = 4.dp,
@@ -743,11 +744,11 @@ private fun RemoteBookItem(
Spacer(modifier = Modifier.width(6.dp)) Spacer(modifier = Modifier.width(6.dp))
} }
Text( AppText(
text = "${ConvertUtils.formatFileSize(book.size)}${ text = "${ConvertUtils.formatFileSize(book.size)}${
AppConst.dateFormat.format(book.lastModify) AppConst.dateFormat.format(book.lastModify)
}", }",
style = MaterialTheme.typography.labelMedium, style = LegadoTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }
@@ -30,7 +30,6 @@ import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -47,12 +46,13 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.legado.app.R import io.legado.app.R
import io.legado.app.ui.book.changecover.ChangeCoverDialog import io.legado.app.ui.book.changecover.ChangeCoverDialog
import io.legado.app.ui.widget.components.AppScaffold 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.TopBarButtonVariant
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.cover.Cover
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem 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.SelectImageContract
import io.legado.app.utils.launch import io.legado.app.utils.launch
import io.legado.app.utils.showDialogFragment import io.legado.app.utils.showDialogFragment
@@ -71,7 +71,7 @@ fun BookInfoEditScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { Text(text = stringResource(id = R.string.book_info_edit)) }, title = stringResource(id = R.string.book_info_edit),
navigationIcon = { navigationIcon = {
TopbarNavigationButton( TopbarNavigationButton(
onClick = onBack, onClick = onBack,
@@ -191,35 +191,35 @@ fun BookInfoEditContent(
OutlinedTextField( OutlinedTextField(
value = uiState.name, value = uiState.name,
onValueChange = { viewModel.onNameChange(it) }, onValueChange = { viewModel.onNameChange(it) },
label = { Text("书名") }, label = { AppText("书名") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField( OutlinedTextField(
value = uiState.author, value = uiState.author,
onValueChange = { viewModel.onAuthorChange(it) }, onValueChange = { viewModel.onAuthorChange(it) },
label = { Text("作者") }, label = { AppText("作者") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField( OutlinedTextField(
value = uiState.coverUrl ?: "", value = uiState.coverUrl ?: "",
onValueChange = { viewModel.onCoverUrlChange(it) }, onValueChange = { viewModel.onCoverUrlChange(it) },
label = { Text("封面链接") }, label = { AppText("封面链接") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField( OutlinedTextField(
value = uiState.intro ?: "", value = uiState.intro ?: "",
onValueChange = { viewModel.onIntroChange(it) }, onValueChange = { viewModel.onIntroChange(it) },
label = { Text("简介") }, label = { AppText("简介") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField( OutlinedTextField(
value = uiState.remark ?: "", value = uiState.remark ?: "",
onValueChange = { viewModel.onRemarkChange(it) }, onValueChange = { viewModel.onRemarkChange(it) },
label = { Text("备注") }, label = { AppText("备注") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
} }
@@ -251,7 +251,7 @@ fun BookTypeDropdown(
state = textFieldState, state = textFieldState,
readOnly = true, readOnly = true,
lineLimits = TextFieldLineLimits.SingleLine, lineLimits = TextFieldLineLimits.SingleLine,
label = { Text("书籍类型") }, label = { AppText("书籍类型") },
trailingIcon = { trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
}, },
@@ -269,7 +269,7 @@ fun BookTypeDropdown(
) { ) {
bookTypes.forEach { option -> bookTypes.forEach { option ->
DropdownMenuItem( DropdownMenuItem(
text = { Text(option) }, text = { AppText(option) },
onClick = { onClick = {
onTypeSelected(option) onTypeSelected(option)
expanded = false expanded = false
@@ -43,7 +43,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -78,11 +77,10 @@ import androidx.compose.ui.zIndex
import cn.hutool.core.date.DateUtil import cn.hutool.core.date.DateUtil
import io.legado.app.data.entities.readRecord.ReadRecord import io.legado.app.data.entities.readRecord.ReadRecord
import io.legado.app.data.entities.readRecord.ReadRecordDetail 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.AnimatedTextLine
import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.AppScaffold
import io.legado.app.ui.widget.components.EmptyMessageView 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.SearchBarSection
import io.legado.app.ui.widget.components.SectionHeader 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.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.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.swipe.SwipeAction 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.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 io.legado.app.utils.StringUtils.formatFriendlyDate
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -148,11 +149,7 @@ fun ReadRecordScreen(
topBar = { topBar = {
Column { Column {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { title = "阅读记录",
Text(
text = "阅读记录"
)
},
subtitle = { subtitle = {
val subTitle = when (displayMode) { val subTitle = when (displayMode) {
DisplayMode.AGGREGATE -> "汇总视图" DisplayMode.AGGREGATE -> "汇总视图"
@@ -271,10 +268,10 @@ fun ReadRecordScreen(
onDismissRequest = { onDismissRequest = {
pendingDeleteAction = null pendingDeleteAction = null
}, },
title = { Text("确认删除") }, title = { AppText("确认删除") },
text = { text = {
Column { Column {
Text("确定要删除这条记录吗?") AppText("确定要删除这条记录吗?")
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Row( Row(
modifier = Modifier modifier = Modifier
@@ -289,10 +286,10 @@ fun ReadRecordScreen(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Checkbox(checked = skipDeleteConfirmTemp, onCheckedChange = null) Checkbox(checked = skipDeleteConfirmTemp, onCheckedChange = null)
Text( AppText(
text = "不再提示", text = "不再提示",
modifier = Modifier.padding(start = 8.dp), modifier = Modifier.padding(start = 8.dp),
style = MaterialTheme.typography.bodyMedium style = LegadoTheme.typography.bodyMedium
) )
} }
} }
@@ -311,7 +308,7 @@ fun ReadRecordScreen(
TextButton(onClick = { TextButton(onClick = {
pendingDeleteAction = null pendingDeleteAction = null
}) { }) {
Text("取消") AppText("取消")
} }
} }
) )
@@ -346,10 +343,10 @@ fun ReadRecordScreen(
AlertDialog( AlertDialog(
onDismissRequest = { mergeDialogData = null }, onDismissRequest = { mergeDialogData = null },
title = { Text("合并阅读记录") }, title = { AppText("合并阅读记录") },
text = { text = {
Column { Column {
Text("将以下作者的“${targetRecord.bookName}”合并到 ${targetRecord.bookAuthor.ifBlank { "未知作者" }}") AppText("将以下作者的“${targetRecord.bookName}”合并到 ${targetRecord.bookAuthor.ifBlank { "未知作者" }}")
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
candidates.forEach { candidate -> candidates.forEach { candidate ->
@@ -367,10 +364,10 @@ fun ReadRecordScreen(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Checkbox(checked = isChecked, onCheckedChange = null) Checkbox(checked = isChecked, onCheckedChange = null)
Text( AppText(
text = "$author${formatDuring(candidate.readTime)}", text = "$author${formatDuring(candidate.readTime)}",
modifier = Modifier.padding(start = 8.dp), modifier = Modifier.padding(start = 8.dp),
style = MaterialTheme.typography.bodyMedium style = LegadoTheme.typography.bodyMedium
) )
} }
} }
@@ -386,12 +383,12 @@ fun ReadRecordScreen(
mergeDialogData = null mergeDialogData = null
} }
) { ) {
Text("合并") AppText("合并")
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { mergeDialogData = null }) { TextButton(onClick = { mergeDialogData = null }) {
Text("取消") AppText("取消")
} }
} }
) )
@@ -686,21 +683,21 @@ fun LatestReadItem(
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text( AppText(
text = record.bookName, text = record.bookName,
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
Text( AppText(
text = record.bookAuthor.ifBlank { "未知作者" }, text = record.bookAuthor.ifBlank { "未知作者" },
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.outline, color = MaterialTheme.colorScheme.outline,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( AppText(
modifier = Modifier modifier = Modifier
.basicMarquee( .basicMarquee(
iterations = Int.MAX_VALUE, iterations = Int.MAX_VALUE,
@@ -716,7 +713,7 @@ fun LatestReadItem(
append("${DateUtil.format(Date(record.lastRead), "yyyy-MM-dd HH:mm")}") append("${DateUtil.format(Date(record.lastRead), "yyyy-MM-dd HH:mm")}")
} }
}, },
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
@@ -783,9 +780,9 @@ fun TimelineSessionItem(
modifier = Modifier.width(48.dp), modifier = Modifier.width(48.dp),
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
Text( AppText(
text = endTimeText, text = endTimeText,
style = MaterialTheme.typography.bodySmall style = LegadoTheme.typography.bodySmall
) )
} }
@@ -795,23 +792,23 @@ fun TimelineSessionItem(
Cover(coverPath) Cover(coverPath)
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Column { Column {
Text( AppText(
text = session.bookName, text = session.bookName,
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
Text( AppText(
text = session.bookAuthor.ifBlank { "未知作者" }, text = session.bookAuthor.ifBlank { "未知作者" },
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.outline, color = MaterialTheme.colorScheme.outline,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( AppText(
text = chapterTitle.orEmpty(), text = chapterTitle.orEmpty(),
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.outline, color = MaterialTheme.colorScheme.outline,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
@@ -847,21 +844,21 @@ fun ReadRecordItem(
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text( AppText(
text = detail.bookName, text = detail.bookName,
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
maxLines = 1 maxLines = 1
) )
Text( AppText(
text = detail.bookAuthor.ifBlank { "未知作者" }, text = detail.bookAuthor.ifBlank { "未知作者" },
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.outline, color = MaterialTheme.colorScheme.outline,
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( AppText(
text = "阅读时长: ${formatDuring(detail.readTime)}", text = "阅读时长: ${formatDuring(detail.readTime)}",
color = MaterialTheme.colorScheme.outline, color = MaterialTheme.colorScheme.outline,
style = MaterialTheme.typography.labelSmall style = LegadoTheme.typography.labelSmall
) )
} }
} }
@@ -876,17 +873,17 @@ fun DateHeader(
SectionHeader( SectionHeader(
titleContent = { titleContent = {
Column { Column {
Text( AppText(
text = dateText, text = dateText,
style = MaterialTheme.typography.bodyMedium, style = LegadoTheme.typography.bodyMedium,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.secondary color = MaterialTheme.colorScheme.secondary
) )
dailyTotalTime?.let { total -> dailyTotalTime?.let { total ->
Text( AppText(
text = "已读 ${formatDuring(total)}", text = "已读 ${formatDuring(total)}",
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurface color = MaterialTheme.colorScheme.onSurface
) )
} }
@@ -934,28 +931,28 @@ fun ReadingSummaryCard(
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text( AppText(
text = title, text = title,
style = MaterialTheme.typography.labelLarge, style = LegadoTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Row(verticalAlignment = Alignment.Bottom) { Row(verticalAlignment = Alignment.Bottom) {
Text( AppText(
text = "已读 ", text = "已读 ",
style = MaterialTheme.typography.titleMedium style = LegadoTheme.typography.titleMedium
) )
Text( AppText(
text = "$bookCount", text = "$bookCount",
style = MaterialTheme.typography.headlineMedium, style = LegadoTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary, color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
) )
Text( AppText(
text = " 本书", text = " 本书",
style = MaterialTheme.typography.titleMedium style = LegadoTheme.typography.titleMedium
) )
} }
@@ -965,9 +962,9 @@ fun ReadingSummaryCard(
val minutes = totalDurationMinutes % 60 val minutes = totalDurationMinutes % 60
val timeString = if (hours > 0) "${hours}小时${minutes}分钟" else "${minutes}分钟" val timeString = if (hours > 0) "${hours}小时${minutes}分钟" else "${minutes}分钟"
Text( AppText(
text = "共阅读 $timeString", text = "共阅读 $timeString",
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }
@@ -44,7 +44,6 @@ import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.PlainTooltip import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Text
import androidx.compose.material3.TooltipAnchorPosition import androidx.compose.material3.TooltipAnchorPosition
import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults 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.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.data.entities.SearchContentHistory 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.AppScaffold
import io.legado.app.ui.widget.components.EmptyMessageView 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.SearchBarSection
import io.legado.app.ui.widget.components.button.SmallAnimatedActionButton import io.legado.app.ui.widget.components.button.SmallAnimatedActionButton
import io.legado.app.ui.widget.components.button.SmallIconButton 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.button.TopbarNavigationButton
import io.legado.app.ui.widget.components.card.TextCard 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.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 kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -140,12 +140,9 @@ fun SearchContentScreen(
topBar = { topBar = {
Column { Column {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { title = if (searchQuery.isNotBlank() && searchResults.isNotEmpty()) {
val title = if (searchQuery.isNotBlank() && searchResults.isNotEmpty()) { "${searchResults.size} 条结果"
"${searchResults.size} 条结果" } else "搜索内容",
} else "搜索内容"
AnimatedText(text = title)
},
navigationIcon = { TopbarNavigationButton(onClick = onBack) }, navigationIcon = { TopbarNavigationButton(onClick = onBack) },
actions = { actions = {
Row( Row(
@@ -191,7 +188,7 @@ fun SearchContentScreen(
), ),
tooltip = { tooltip = {
PlainTooltip { PlainTooltip {
Text(if (isSearching) "停止搜索" else "跳转到当前章节") AppText(if (isSearching) "停止搜索" else "跳转到当前章节")
} }
}, },
state = rememberTooltipState(), state = rememberTooltipState(),
@@ -310,9 +307,9 @@ fun SearchHistoryList(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
) { ) {
Text( AppText(
text = "搜索历史", text = "搜索历史",
style = MaterialTheme.typography.titleSmallEmphasized, style = LegadoTheme.typography.titleSmallEmphasized,
color = MaterialTheme.colorScheme.primary, color = MaterialTheme.colorScheme.primary,
modifier = Modifier.align(Alignment.Center) modifier = Modifier.align(Alignment.Center)
) )
@@ -342,7 +339,7 @@ fun SearchHistoryList(
.clickable { onHistoryClick(item) } .clickable { onHistoryClick(item) }
.animateItem(), .animateItem(),
headlineContent = { headlineContent = {
Text( AppText(
text = item.query, text = item.query,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
@@ -378,7 +375,7 @@ fun SearchHistoryList(
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
Spacer(Modifier.width(8.dp)) Spacer(Modifier.width(8.dp))
Text("清除搜索历史") AppText("清除搜索历史")
} }
} }
} }
@@ -407,7 +404,7 @@ fun SearchResultItem(
Box(modifier = Modifier.padding(16.dp)) { Box(modifier = Modifier.padding(16.dp)) {
Column { Column {
Text( AppText(
text = buildAnnotatedString { text = buildAnnotatedString {
append( append(
result.getTitleSpannable( result.getTitleSpannable(
@@ -415,14 +412,14 @@ fun SearchResultItem(
) )
) )
}, },
style = MaterialTheme.typography.titleSmall style = LegadoTheme.typography.titleSmall
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
HorizontalDivider() HorizontalDivider()
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( AppText(
text = buildAnnotatedString { text = buildAnnotatedString {
append( append(
result.getContentSpannable( result.getContentSpannable(
@@ -432,7 +429,7 @@ fun SearchResultItem(
) )
) )
}, },
style = MaterialTheme.typography.bodyMedium style = LegadoTheme.typography.bodyMedium
) )
} }
@@ -63,7 +63,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.PrimaryScrollableTabRow
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Tab import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.material3.ToggleFloatingActionButton import androidx.compose.material3.ToggleFloatingActionButton
import androidx.compose.material3.ToggleFloatingActionButtonDefaults.animateIcon import androidx.compose.material3.ToggleFloatingActionButtonDefaults.animateIcon
import androidx.compose.material3.animateFloatingActionButton 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.help.book.isLocal
import io.legado.app.ui.book.toc.rule.TxtTocRuleActivity import io.legado.app.ui.book.toc.rule.TxtTocRuleActivity
import io.legado.app.ui.replace.ReplaceEditRoute 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.CollapsibleHeader
import io.legado.app.ui.widget.components.ActionItem import io.legado.app.ui.widget.components.ActionItem
import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.AppScaffold
import io.legado.app.ui.widget.components.EmptyMessageView 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.SelectionBottomBar
import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet
import io.legado.app.ui.widget.components.bookmark.BookmarkItem 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.lazylist.FastScrollLazyColumn
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu 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.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.DynamicTopAppBar
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -312,33 +313,33 @@ fun TocScreen(
when (pagerState.currentPage) { when (pagerState.currentPage) {
0 -> { 0 -> {
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("使用替换规则") }, text = { AppText("使用替换规则") },
trailingIcon = { trailingIcon = {
Checkbox(checked = useReplace, onCheckedChange = null) Checkbox(checked = useReplace, onCheckedChange = null)
}, },
onClick = { viewModel.toggleUseReplace() } onClick = { viewModel.toggleUseReplace() }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("显示字数") }, text = { AppText("显示字数") },
trailingIcon = { trailingIcon = {
Checkbox(checked = showWordCount, onCheckedChange = null) Checkbox(checked = showWordCount, onCheckedChange = null)
}, },
onClick = { viewModel.toggleShowWordCount() } onClick = { viewModel.toggleShowWordCount() }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("反转目录") }, text = { AppText("反转目录") },
onClick = { viewModel.reverseToc() } onClick = { viewModel.reverseToc() }
) )
PillDivider() PillDivider()
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("替换规则") }, text = { AppText("替换规则") },
onClick = { onClick = {
onOpenReplaceRule(null) onOpenReplaceRule(null)
dismiss() dismiss()
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("新建替换规则") }, text = { AppText("新建替换规则") },
onClick = { onClick = {
val scopes = mutableListOf<String>() val scopes = mutableListOf<String>()
book?.name?.let { scopes.add(it) } book?.name?.let { scopes.add(it) }
@@ -358,7 +359,7 @@ fun TocScreen(
if (book?.isLocal == true) { if (book?.isLocal == true) {
PillHeaderDivider(title = "本地书籍选项") PillHeaderDivider(title = "本地书籍选项")
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("本地书籍目录规则") }, text = { AppText("本地书籍目录规则") },
onClick = { onClick = {
val intent = val intent =
Intent(context, TxtTocRuleActivity::class.java).apply { Intent(context, TxtTocRuleActivity::class.java).apply {
@@ -369,7 +370,7 @@ fun TocScreen(
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("拆分超长章节") }, text = { AppText("拆分超长章节") },
trailingIcon = { trailingIcon = {
Checkbox( Checkbox(
checked = viewModel.isSplitLongChapter, checked = viewModel.isSplitLongChapter,
@@ -386,7 +387,7 @@ fun TocScreen(
else -> { else -> {
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("导出书签为JSON") }, text = { AppText("导出书签为JSON") },
onClick = { onClick = {
val dateFormat = SimpleDateFormat( val dateFormat = SimpleDateFormat(
"yyyyMMdd_HHmm", "yyyyMMdd_HHmm",
@@ -398,7 +399,7 @@ fun TocScreen(
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("导出书签为MarkDown") }, text = { AppText("导出书签为MarkDown") },
onClick = { onClick = {
val dateFormat = SimpleDateFormat( val dateFormat = SimpleDateFormat(
"yyyyMMdd_HHmm", "yyyyMMdd_HHmm",
@@ -428,7 +429,7 @@ fun TocScreen(
selected = pagerState.currentPage == 0, selected = pagerState.currentPage == 0,
onClick = { scope.launch { pagerState.animateScrollToPage(0) } }, onClick = { scope.launch { pagerState.animateScrollToPage(0) } },
text = { text = {
Text( AppText(
text = "目录", text = "目录",
modifier = Modifier.padding(horizontal = 16.dp), modifier = Modifier.padding(horizontal = 16.dp),
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -439,7 +440,7 @@ fun TocScreen(
selected = pagerState.currentPage == 1, selected = pagerState.currentPage == 1,
onClick = { scope.launch { pagerState.animateScrollToPage(1) } }, onClick = { scope.launch { pagerState.animateScrollToPage(1) } },
text = { text = {
Text( AppText(
text = "书签", text = "书签",
modifier = Modifier.padding(horizontal = 16.dp), modifier = Modifier.padding(horizontal = 16.dp),
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -464,13 +465,13 @@ fun TocScreen(
onDismissRequest = { showVolumeMenu = false } onDismissRequest = { showVolumeMenu = false }
) { ) {
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("展开所有卷") }, text = { AppText("展开所有卷") },
onClick = { onClick = {
viewModel.expandAllVolumes(); showVolumeMenu = false viewModel.expandAllVolumes(); showVolumeMenu = false
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("收起所有卷") }, text = { AppText("收起所有卷") },
onClick = { onClick = {
viewModel.collapseAllVolumes(); showVolumeMenu = false viewModel.collapseAllVolumes(); showVolumeMenu = false
} }
@@ -482,7 +483,7 @@ fun TocScreen(
PillHeaderDivider(title = "快速跳转") PillHeaderDivider(title = "快速跳转")
volumeItems.forEach { uiItem -> volumeItems.forEach { uiItem ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(uiItem.title) }, text = { AppText(uiItem.title) },
onClick = { onClick = {
scope.launch { scope.launch {
val targetIndex = val targetIndex =
@@ -541,7 +542,7 @@ fun TocScreen(
fabMenuExpanded = false fabMenuExpanded = false
}, },
icon = { Icon(icon, contentDescription = null) }, icon = { Icon(icon, contentDescription = null) },
text = { Text(text = label) } text = { AppText(text = label) }
) )
} }
} }
@@ -729,9 +730,9 @@ fun ChapterItem(
) )
} }
Text( AppText(
text = item.title, text = item.title,
style = MaterialTheme.typography.bodyMediumEmphasized.copy(fontWeight = FontWeight.Medium), style = LegadoTheme.typography.bodyMediumEmphasized.copy(fontWeight = FontWeight.Medium),
color = textColor, color = textColor,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
@@ -739,9 +740,9 @@ fun ChapterItem(
} }
if (!item.tag.isNullOrEmpty()) { if (!item.tag.isNullOrEmpty()) {
Text( AppText(
text = item.tag, text = item.tag,
style = MaterialTheme.typography.labelSmallEmphasized, style = LegadoTheme.typography.labelSmallEmphasized,
color = detailColor.copy(alpha = 0.8f), color = detailColor.copy(alpha = 0.8f),
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
@@ -910,11 +911,11 @@ private fun StatusIcon(
color = Color.Transparent color = Color.Transparent
) { ) {
if (wordCount != null) { if (wordCount != null) {
Text( AppText(
modifier = Modifier modifier = Modifier
.padding(horizontal = 8.dp, vertical = 4.dp), .padding(horizontal = 8.dp, vertical = 4.dp),
text = wordCount, text = wordCount,
style = MaterialTheme.typography.labelSmall.copy(fontSize = 9.sp), style = LegadoTheme.typography.labelSmall.copy(fontSize = 9.sp),
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }
@@ -19,11 +19,9 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -46,6 +44,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseRuleEvent import io.legado.app.base.BaseRuleEvent
import io.legado.app.data.entities.TxtTocRule 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.ActionItem
import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.DraggableSelectionHandler
import io.legado.app.ui.widget.components.button.SmallIconButton 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.RuleEditFields
import io.legado.app.ui.widget.components.rules.RuleEditSheet 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.rules.RuleListScaffold
import io.legado.app.ui.widget.components.text.AppText
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
import sh.calvin.reorderable.rememberReorderableLazyListState import sh.calvin.reorderable.rememberReorderableLazyListState
@@ -196,8 +196,8 @@ fun TxtRuleScreen(
onConfirm = { viewModel.saveImportedRules() }, onConfirm = { viewModel.saveImportedRules() },
itemContent = { rule, _ -> itemContent = { rule, _ ->
Column { Column {
Text(rule.name, style = MaterialTheme.typography.titleMedium) AppText(rule.name, style = LegadoTheme.typography.titleMedium)
Text(rule.rule, style = MaterialTheme.typography.bodySmall, maxLines = 1) AppText(rule.rule, style = LegadoTheme.typography.bodySmall, maxLines = 1)
} }
} }
) )
@@ -212,16 +212,16 @@ fun TxtRuleScreen(
showDeleteRuleDialog?.let { rule -> showDeleteRuleDialog?.let { rule ->
AlertDialog( AlertDialog(
onDismissRequest = { showDeleteRuleDialog = null }, onDismissRequest = { showDeleteRuleDialog = null },
title = { Text(stringResource(R.string.delete)) }, title = { AppText(stringResource(R.string.delete)) },
text = { Text(stringResource(R.string.del_msg)) }, text = { AppText(stringResource(R.string.del_msg)) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = { OutlinedButton(onClick = {
viewModel.delete(rule); showDeleteRuleDialog = null viewModel.delete(rule); showDeleteRuleDialog = null
}) { Text(stringResource(R.string.ok)) } }) { AppText(stringResource(R.string.ok)) }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { showDeleteRuleDialog = null }) { TextButton(onClick = { showDeleteRuleDialog = null }) {
Text( AppText(
stringResource(R.string.cancel) stringResource(R.string.cancel)
) )
} }
@@ -312,7 +312,7 @@ fun TxtRuleScreen(
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
dropDownMenuContent = { dismiss -> dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_str)) }, text = { AppText(stringResource(R.string.import_str)) },
onClick = { showImportSheet = true; dismiss() }, onClick = { showImportSheet = true; dismiss() },
leadingIcon = { Icon(Icons.Default.FileOpen, null) } leadingIcon = { Icon(Icons.Default.FileOpen, null) }
) )
@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -14,11 +13,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.ui.widget.components.AppScaffold 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.SplicedColumnGroup
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.ClickableSettingItem
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -36,7 +35,7 @@ fun ConfigNavScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { Text(stringResource(R.string.setting)) }, title = stringResource(R.string.setting),
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBackClick) TopbarNavigationButton(onClick = onBackClick)
@@ -19,7 +19,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable 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.Permissions
import io.legado.app.lib.permission.PermissionsCompat import io.legado.app.lib.permission.PermissionsCompat
import io.legado.app.ui.widget.components.AppScaffold 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.SplicedColumnGroup
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.filePicker.FilePickerSheet
import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem 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.InputSettingItem
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem 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.isContentScheme
import io.legado.app.utils.takePersistablePermissionSafely import io.legado.app.utils.takePersistablePermissionSafely
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -166,9 +166,7 @@ fun BackupConfigScreen(
}, },
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { title = stringResource(R.string.backup_restore),
Text(stringResource(R.string.backup_restore))
},
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBackClick) TopbarNavigationButton(onClick = onBackClick)
@@ -387,19 +385,19 @@ fun BackupConfigScreen(
if (showWebDavAuthDialog) { if (showWebDavAuthDialog) {
AlertDialog( AlertDialog(
onDismissRequest = { showWebDavAuthDialog = false }, onDismissRequest = { showWebDavAuthDialog = false },
title = { Text(stringResource(R.string.web_dav_account)) }, title = { AppText(stringResource(R.string.web_dav_account)) },
text = { text = {
Column { Column {
TextField( TextField(
value = tempAccount, value = tempAccount,
onValueChange = { tempAccount = it }, onValueChange = { tempAccount = it },
label = { Text("账号") } label = { AppText("账号") }
) )
Spacer(modifier = Modifier.padding(8.dp)) Spacer(modifier = Modifier.padding(8.dp))
TextField( TextField(
value = tempPassword, value = tempPassword,
onValueChange = { tempPassword = it }, onValueChange = { tempPassword = it },
label = { Text("密码") }, label = { AppText("密码") },
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = { trailingIcon = {
@@ -432,12 +430,12 @@ fun BackupConfigScreen(
} }
} }
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { showWebDavAuthDialog = false }) { TextButton(onClick = { showWebDavAuthDialog = false }) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -484,7 +482,7 @@ fun BackupConfigScreen(
if (showRestoreSheet && backupNames.isNotEmpty()) { if (showRestoreSheet && backupNames.isNotEmpty()) {
AlertDialog( AlertDialog(
onDismissRequest = { showRestoreSheet = false }, onDismissRequest = { showRestoreSheet = false },
title = { Text(stringResource(R.string.select_restore_file)) }, title = { AppText(stringResource(R.string.select_restore_file)) },
text = { text = {
Column { Column {
backupNames.forEach { name -> backupNames.forEach { name ->
@@ -508,7 +506,7 @@ fun BackupConfigScreen(
} }
) )
}) { }) {
Text(name) AppText(name)
} }
} }
} }
@@ -516,7 +514,7 @@ fun BackupConfigScreen(
confirmButton = {}, confirmButton = {},
dismissButton = { dismissButton = {
TextButton(onClick = { showRestoreSheet = false }) { 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() io.legado.app.help.storage.BackupConfig.saveIgnoreConfig()
showBackupIgnoreDialog = false showBackupIgnoreDialog = false
}, },
title = { Text(stringResource(R.string.restore_ignore)) }, title = { AppText(stringResource(R.string.restore_ignore)) },
text = { text = {
Column { Column {
io.legado.app.help.storage.BackupConfig.ignoreTitle.forEachIndexed { index, title -> io.legado.app.help.storage.BackupConfig.ignoreTitle.forEachIndexed { index, title ->
@@ -546,7 +544,7 @@ fun BackupConfigScreen(
] = checkedItems[index] ] = checkedItems[index]
}) { }) {
val isChecked = 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() io.legado.app.help.storage.BackupConfig.saveIgnoreConfig()
showBackupIgnoreDialog = false showBackupIgnoreDialog = false
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
@@ -564,7 +562,7 @@ fun BackupConfigScreen(
io.legado.app.help.storage.BackupConfig.saveIgnoreConfig() io.legado.app.help.storage.BackupConfig.saveIgnoreConfig()
showBackupIgnoreDialog = false showBackupIgnoreDialog = false
}) { }) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -573,7 +571,7 @@ fun BackupConfigScreen(
if (showLoadingDialog) { if (showLoadingDialog) {
AlertDialog( AlertDialog(
onDismissRequest = {}, onDismissRequest = {},
title = { Text(loadingText) }, title = { AppText(loadingText) },
confirmButton = {}, confirmButton = {},
dismissButton = {} dismissButton = {}
) )
@@ -589,16 +587,16 @@ fun ConfirmDialog(
) { ) {
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text(title) }, title = { AppText(title) },
text = { Text(text) }, text = { AppText(text) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = onConfirm) { OutlinedButton(onClick = onConfirm) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismiss) { TextButton(onClick = onDismiss) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -12,7 +12,6 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -27,14 +26,14 @@ import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.ui.widget.components.AppScaffold 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.SplicedColumnGroup
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.dialog.ColorPickerSheet
import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem 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.DropdownListSettingItem
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem 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 import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -52,7 +51,7 @@ fun CoverConfigScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { Text(stringResource(R.string.cover_config)) }, title = stringResource(R.string.cover_config),
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBackClick) TopbarNavigationButton(onClick = onBackClick)
@@ -22,7 +22,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -36,8 +35,10 @@ import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage import coil.compose.AsyncImage
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.PreferKey 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.filePicker.FilePickerSheet
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -69,9 +70,9 @@ fun CoverManageSheet(
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 24.dp) .padding(bottom = 24.dp)
) { ) {
Text( AppText(
text = stringResource(R.string.default_cover), text = stringResource(R.string.default_cover),
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) )
@@ -11,7 +11,6 @@ import androidx.compose.material3.Checkbox
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -25,8 +24,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.model.BookCover 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.GlassModalBottomSheet
import io.legado.app.ui.widget.components.settingItem.InputSettingItem 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 io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -58,9 +59,9 @@ fun CoverRuleConfigSheet(
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .padding(16.dp)
) { ) {
Text( AppText(
text = stringResource(R.string.cover_rule), text = stringResource(R.string.cover_rule),
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
modifier = Modifier.padding(bottom = 16.dp) modifier = Modifier.padding(bottom = 16.dp)
) )
@@ -72,7 +73,7 @@ fun CoverRuleConfigSheet(
checked = enable, checked = enable,
onCheckedChange = { enable = it } onCheckedChange = { enable = it }
) )
Text(text = stringResource(R.string.enable)) AppText(text = stringResource(R.string.enable))
} }
InputSettingItem( InputSettingItem(
@@ -97,13 +98,16 @@ fun CoverRuleConfigSheet(
BookCover.delCoverRule() BookCover.delCoverRule()
onDismissRequest() onDismissRequest()
}) { }) {
Text(stringResource(R.string.delete), color = MaterialTheme.colorScheme.error) AppText(
stringResource(R.string.delete),
color = MaterialTheme.colorScheme.error
)
} }
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
OutlinedButton(onClick = onDismissRequest) { OutlinedButton(onClick = onDismissRequest) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
Spacer(modifier = Modifier.padding(horizontal = 4.dp)) Spacer(modifier = Modifier.padding(horizontal = 4.dp))
@@ -118,7 +122,7 @@ fun CoverRuleConfigSheet(
onDismissRequest() onDismissRequest()
} }
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
} }
} }
@@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme 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.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier 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.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R 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.CheckboxGroupContainer
import io.legado.app.ui.widget.components.checkBox.CheckboxItem 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.GlassModalBottomSheet
@@ -41,9 +42,9 @@ fun CheckSourceBottomSheet(
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.padding(bottom = 32.dp) .padding(bottom = 32.dp)
) { ) {
Text( AppText(
text = stringResource(R.string.check_source_config), text = stringResource(R.string.check_source_config),
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
modifier = Modifier.padding(vertical = 16.dp) modifier = Modifier.padding(vertical = 16.dp)
) )
@@ -131,7 +132,7 @@ fun CheckSourceBottomSheet(
horizontalArrangement = Arrangement.End horizontalArrangement = Arrangement.End
) { ) {
TextButton(onClick = onDismiss) { TextButton(onClick = onDismiss) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
Button(onClick = { Button(onClick = {
if (viewModel.saveCheckSourceConfig()) { if (viewModel.saveCheckSourceConfig()) {
@@ -140,7 +141,7 @@ fun CheckSourceBottomSheet(
Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show()
} }
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
} }
} }
@@ -24,7 +24,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -41,8 +40,10 @@ import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.help.DirectLinkUpload import io.legado.app.help.DirectLinkUpload
import io.legado.app.lib.dialogs.selector 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.checkBox.CheckboxItem
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet 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.GSON
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.getClipText import io.legado.app.utils.getClipText
@@ -75,9 +76,9 @@ fun DirectLinkUploadBottomSheet(
) { ) {
CenterAlignedTopAppBar( CenterAlignedTopAppBar(
title = { title = {
Text( AppText(
text = stringResource(R.string.direct_link_upload_config), text = stringResource(R.string.direct_link_upload_config),
style = MaterialTheme.typography.titleLarge style = LegadoTheme.typography.titleLarge
) )
}, },
actions = { actions = {
@@ -89,7 +90,7 @@ fun DirectLinkUploadBottomSheet(
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuItem(
text = { Text("导入默认") }, text = { AppText("导入默认") },
leadingIcon = { Icon(Icons.Default.Download, null) }, leadingIcon = { Icon(Icons.Default.Download, null) },
onClick = { onClick = {
showMenu = false showMenu = false
@@ -99,7 +100,7 @@ fun DirectLinkUploadBottomSheet(
} }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.copy_rule)) }, text = { AppText(stringResource(R.string.copy_rule)) },
leadingIcon = { Icon(Icons.Default.ContentCopy, null) }, leadingIcon = { Icon(Icons.Default.ContentCopy, null) },
onClick = { onClick = {
showMenu = false showMenu = false
@@ -113,7 +114,7 @@ fun DirectLinkUploadBottomSheet(
} }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.paste_rule)) }, text = { AppText(stringResource(R.string.paste_rule)) },
leadingIcon = { Icon(Icons.Default.ContentPaste, null) }, leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
onClick = { onClick = {
showMenu = false showMenu = false
@@ -141,7 +142,7 @@ fun DirectLinkUploadBottomSheet(
OutlinedTextField( OutlinedTextField(
value = viewModel.uploadUrl, value = viewModel.uploadUrl,
onValueChange = { viewModel.uploadUrl = it }, onValueChange = { viewModel.uploadUrl = it },
label = { Text(stringResource(R.string.upload_url)) }, label = { AppText(stringResource(R.string.upload_url)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
@@ -150,7 +151,7 @@ fun DirectLinkUploadBottomSheet(
OutlinedTextField( OutlinedTextField(
value = viewModel.downloadUrlRule, value = viewModel.downloadUrlRule,
onValueChange = { viewModel.downloadUrlRule = it }, onValueChange = { viewModel.downloadUrlRule = it },
label = { Text(stringResource(R.string.download_url_rule)) }, label = { AppText(stringResource(R.string.download_url_rule)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
@@ -159,7 +160,7 @@ fun DirectLinkUploadBottomSheet(
OutlinedTextField( OutlinedTextField(
value = viewModel.summary, value = viewModel.summary,
onValueChange = { viewModel.summary = it }, onValueChange = { viewModel.summary = it },
label = { Text(stringResource(R.string.summary)) }, label = { AppText(stringResource(R.string.summary)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
@@ -178,11 +179,11 @@ fun DirectLinkUploadBottomSheet(
TextButton(onClick = { TextButton(onClick = {
viewModel.testRule { result -> showTestResult = result } viewModel.testRule { result -> showTestResult = result }
}) { }) {
Text("测试") AppText("测试")
} }
Spacer(Modifier.weight(1f)) Spacer(Modifier.weight(1f))
OutlinedButton(onClick = onDismiss) { OutlinedButton(onClick = onDismiss) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
Button(onClick = { Button(onClick = {
if (viewModel.saveDirectLinkRule()) { if (viewModel.saveDirectLinkRule()) {
@@ -191,7 +192,7 @@ fun DirectLinkUploadBottomSheet(
context.toastOnUi("请填写完整信息") context.toastOnUi("请填写完整信息")
} }
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
} }
} }
@@ -200,15 +201,15 @@ fun DirectLinkUploadBottomSheet(
showTestResult?.let { result -> showTestResult?.let { result ->
AlertDialog( AlertDialog(
onDismissRequest = { showTestResult = null }, onDismissRequest = { showTestResult = null },
title = { Text("Result") }, title = { AppText("Result") },
text = { Text(result) }, text = { AppText(result) },
confirmButton = { confirmButton = {
TextButton(onClick = { TextButton(onClick = {
showTestResult = null showTestResult = null
}) { Text(stringResource(R.string.ok)) } }) { AppText(stringResource(R.string.ok)) }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { context.sendToClip(result) }) { Text(stringResource(R.string.copy_text)) } TextButton(onClick = { context.sendToClip(result) }) { AppText(stringResource(R.string.copy_text)) }
} }
) )
} }
@@ -13,7 +13,6 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -30,8 +29,6 @@ import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.service.WebService import io.legado.app.service.WebService
import io.legado.app.ui.widget.components.AppScaffold 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.SplicedColumnGroup
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.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.InputSettingItem
import io.legado.app.ui.widget.components.settingItem.SliderSettingItem 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.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.restart
import io.legado.app.utils.takePersistablePermissionSafely import io.legado.app.utils.takePersistablePermissionSafely
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -83,9 +83,7 @@ fun OtherConfigScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { title = stringResource(R.string.other_setting),
Text(stringResource(R.string.other_setting))
},
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBackClick) TopbarNavigationButton(onClick = onBackClick)
@@ -200,7 +198,10 @@ fun OtherConfigScreen(
SliderSettingItem( SliderSettingItem(
title = stringResource(R.string.bitmap_cache_size), 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(), value = OtherConfig.bitmapCacheSize.toFloat(),
defaultValue = 32f, defaultValue = 32f,
valueRange = 1f..2047f, valueRange = 1f..2047f,
@@ -211,7 +212,10 @@ fun OtherConfigScreen(
SliderSettingItem( SliderSettingItem(
title = stringResource(R.string.image_retain_number), 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(), value = OtherConfig.imageRetainNum.toFloat(),
defaultValue = 10f, defaultValue = 10f,
valueRange = 0f..100f, valueRange = 0f..100f,
@@ -220,7 +224,10 @@ fun OtherConfigScreen(
SliderSettingItem( SliderSettingItem(
title = stringResource(R.string.pre_download), 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(), value = OtherConfig.preDownloadNum.toFloat(),
defaultValue = 10f, defaultValue = 10f,
valueRange = 0f..100f, valueRange = 0f..100f,
@@ -458,23 +465,23 @@ fun OtherConfigScreen(
if (showPasswordDialog) { if (showPasswordDialog) {
AlertDialog( AlertDialog(
onDismissRequest = { showPasswordDialog = false }, onDismissRequest = { showPasswordDialog = false },
title = { Text(stringResource(R.string.set_local_password)) }, title = { AppText(stringResource(R.string.set_local_password)) },
text = { text = {
TextField( TextField(
value = tempPassword, value = tempPassword,
onValueChange = { tempPassword = it }, onValueChange = { tempPassword = it },
label = { Text("Password") } label = { AppText("Password") }
) )
}, },
confirmButton = { confirmButton = {
TextButton(onClick = { TextButton(onClick = {
viewModel.setLocalPassword(tempPassword) viewModel.setLocalPassword(tempPassword)
showPasswordDialog = false showPasswordDialog = false
}) { Text(stringResource(R.string.ok)) } }) { AppText(stringResource(R.string.ok)) }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { showPasswordDialog = false }) { TextButton(onClick = { showPasswordDialog = false }) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -492,16 +499,16 @@ fun ConfirmDialog(
) { ) {
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text(title) }, title = { AppText(title) },
text = { Text(text) }, text = { AppText(text) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = onConfirm) { OutlinedButton(onClick = onConfirm) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismiss) { TextButton(onClick = onDismiss) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -11,7 +11,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf 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.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R 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.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -40,16 +41,16 @@ fun PageKeySheet(
.padding(16.dp), .padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
Text( AppText(
text = stringResource(R.string.custom_page_key), text = stringResource(R.string.custom_page_key),
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
fontWeight = FontWeight.Companion.Bold fontWeight = FontWeight.Companion.Bold
) )
OutlinedTextField( OutlinedTextField(
value = prevKeys, value = prevKeys,
onValueChange = { prevKeys = it }, onValueChange = { prevKeys = it },
label = { Text(stringResource(R.string.prev_page_key)) }, label = { AppText(stringResource(R.string.prev_page_key)) },
modifier = Modifier.Companion modifier = Modifier.Companion
.fillMaxWidth() .fillMaxWidth()
.onPreviewKeyEvent { event -> .onPreviewKeyEvent { event ->
@@ -72,7 +73,7 @@ fun PageKeySheet(
OutlinedTextField( OutlinedTextField(
value = nextKeys, value = nextKeys,
onValueChange = { nextKeys = it }, onValueChange = { nextKeys = it },
label = { Text(stringResource(R.string.next_page_key)) }, label = { AppText(stringResource(R.string.next_page_key)) },
modifier = Modifier.Companion modifier = Modifier.Companion
.fillMaxWidth() .fillMaxWidth()
.onPreviewKeyEvent { event -> .onPreviewKeyEvent { event ->
@@ -92,9 +93,9 @@ fun PageKeySheet(
singleLine = true singleLine = true
) )
Text( AppText(
text = stringResource(R.string.page_key_set_help), text = stringResource(R.string.page_key_set_help),
style = MaterialTheme.typography.bodyMedium, style = LegadoTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
@@ -109,7 +110,7 @@ fun PageKeySheet(
}, },
modifier = Modifier.Companion.weight(1f) modifier = Modifier.Companion.weight(1f)
) { ) {
Text(stringResource(R.string.reset)) AppText(stringResource(R.string.reset))
} }
Button( Button(
@@ -120,7 +121,7 @@ fun PageKeySheet(
}, },
modifier = Modifier.Companion.weight(1f) modifier = Modifier.Companion.weight(1f)
) { ) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
} }
} }
@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -20,14 +19,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.ui.widget.components.AppScaffold 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.SplicedColumnGroup
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.ClickableSettingItem
import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem 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.SliderSettingItem
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem 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 io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -45,9 +44,7 @@ fun ReadConfigScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { title = stringResource(R.string.read_config),
Text(stringResource(R.string.read_config))
},
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBackClick) TopbarNavigationButton(onClick = onBackClick)
@@ -17,7 +17,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -31,8 +30,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage import coil.compose.AsyncImage
import io.legado.app.R 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.filePicker.FilePickerSheet
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -72,9 +73,9 @@ fun BackgroundImageManageSheet(
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 24.dp) .padding(bottom = 24.dp)
) { ) {
Text( AppText(
text = stringResource(R.string.background_image), text = stringResource(R.string.background_image),
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) )
@@ -20,7 +20,6 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment 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.Launcher5
import io.legado.app.ui.main.Launcher6 import io.legado.app.ui.main.Launcher6
import io.legado.app.ui.main.LauncherW 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.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getCompatDrawable
import splitties.init.appCtx import splitties.init.appCtx
@@ -61,9 +62,9 @@ fun LauncherIconPickerSheet(
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 24.dp) .padding(bottom = 24.dp)
) { ) {
Text( AppText(
text = stringResource(R.string.change_icon), text = stringResource(R.string.change_icon),
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) )
@@ -21,6 +21,9 @@ object ThemeConfig {
var paletteStyle by prefDelegate(PreferKey.paletteStyle, "tonalSpot") 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 materialVersion by prefDelegate(PreferKey.materialVersion, "material3")
var appTheme by prefDelegate(PreferKey.appTheme, "0") var appTheme by prefDelegate(PreferKey.appTheme, "0")
@@ -44,7 +44,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.ToggleButton import androidx.compose.material3.ToggleButton
import androidx.compose.material3.ToggleButtonDefaults 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.help.config.OldThemeConfig
import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.ThemeStore
import io.legado.app.lib.theme.primaryColor 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.ThemeManager
import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.theme.ThemeResolver
import io.legado.app.ui.widget.components.AppScaffold 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.SplicedColumnGroup
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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.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.DropdownListSettingItem
import io.legado.app.ui.widget.components.settingItem.SliderSettingItem 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.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.postEvent
import io.legado.app.utils.restart import io.legado.app.utils.restart
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
@@ -121,7 +122,7 @@ fun ThemeConfigScreen(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { Text(stringResource(R.string.theme_setting)) }, title = stringResource(R.string.theme_setting),
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBackClick) TopbarNavigationButton(onClick = onBackClick)
@@ -226,6 +227,13 @@ fun ThemeConfigScreen(
context.toastOnUi(R.string.restart_to_apply) 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( SliderSettingItem(
title = stringResource(R.string.font_scale), title = stringResource(R.string.font_scale),
description = stringResource( description = stringResource(
@@ -478,7 +486,7 @@ fun ThemeConfigScreen(
if (showRestartDialog) { if (showRestartDialog) {
AlertDialog( AlertDialog(
onDismissRequest = { showRestartDialog = false }, onDismissRequest = { showRestartDialog = false },
title = { Text(stringResource(R.string.restart_required_message)) }, title = { AppText(stringResource(R.string.restart_required_message)) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = { OutlinedButton(onClick = {
showRestartDialog = false showRestartDialog = false
@@ -486,7 +494,7 @@ fun ThemeConfigScreen(
context.restart() context.restart()
}, 100) }, 100)
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
@@ -494,7 +502,7 @@ fun ThemeConfigScreen(
showRestartDialog = false showRestartDialog = false
context.toastOnUi(R.string.restart_later_message) 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 -> saveThemeKey?.let { key ->
AlertDialog( AlertDialog(
onDismissRequest = { saveThemeKey = null }, onDismissRequest = { saveThemeKey = null },
title = { Text(stringResource(R.string.theme_name)) }, title = { AppText(stringResource(R.string.theme_name)) },
text = { text = {
OutlinedTextField( OutlinedTextField(
value = themeName, value = themeName,
onValueChange = { themeName = it }, onValueChange = { themeName = it },
label = { Text("name") }, label = { AppText("name") },
singleLine = true singleLine = true
) )
}, },
@@ -566,12 +574,12 @@ fun ThemeConfigScreen(
saveThemeKey = null saveThemeKey = null
} }
) { ) {
Text(stringResource(android.R.string.ok)) AppText(stringResource(android.R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { saveThemeKey = null }) { 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)) Spacer(Modifier.size(ToggleButtonDefaults.IconSpacing))
Text(text = label) AppText(text = label)
} }
} }
} }
@@ -745,9 +753,9 @@ fun ThemeColorButton(
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
Text( AppText(
text = label, text = label,
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
) )
} }
@@ -15,12 +15,10 @@ import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.FileDownload import androidx.compose.material.icons.filled.FileDownload
import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -38,8 +36,10 @@ import androidx.core.graphics.toColorInt
import io.legado.app.R import io.legado.app.R
import io.legado.app.help.config.OldThemeConfig import io.legado.app.help.config.OldThemeConfig
import io.legado.app.lib.theme.primaryColor 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.card.GlassCard
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet 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.GSON
import io.legado.app.utils.getClipText import io.legado.app.utils.getClipText
import io.legado.app.utils.share 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), .padding(start = 16.dp, end = 8.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text( AppText(
text = stringResource(R.string.theme_list), text = stringResource(R.string.theme_list),
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
IconButton( IconButton(
@@ -104,13 +104,11 @@ fun ThemeListDialog(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
shape = RoundedCornerShape(20.dp), shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors( containerColor = if (item.primaryColor.toColorInt() == context.primaryColor) {
containerColor = if (item.primaryColor.toColorInt() == context.primaryColor) { MaterialTheme.colorScheme.secondaryContainer
MaterialTheme.colorScheme.secondaryContainer } else {
} else { MaterialTheme.colorScheme.surfaceContainer
MaterialTheme.colorScheme.surfaceContainer }
}
)
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@@ -129,9 +127,9 @@ fun ThemeListDialog(
) )
.padding(8.dp) .padding(8.dp)
) )
Text( AppText(
text = item.themeName, text = item.themeName,
style = MaterialTheme.typography.bodyLarge, style = LegadoTheme.typography.bodyLarge,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
IconButton( IconButton(
@@ -161,8 +159,8 @@ fun ThemeListDialog(
deleteIndex?.let { index -> deleteIndex?.let { index ->
AlertDialog( AlertDialog(
onDismissRequest = { deleteIndex = null }, onDismissRequest = { deleteIndex = null },
title = { Text(stringResource(R.string.delete)) }, title = { AppText(stringResource(R.string.delete)) },
text = { Text(stringResource(R.string.sure_del)) }, text = { AppText(stringResource(R.string.sure_del)) },
confirmButton = { confirmButton = {
TextButton( TextButton(
onClick = { onClick = {
@@ -171,12 +169,12 @@ fun ThemeListDialog(
deleteIndex = null deleteIndex = null
} }
) { ) {
Text(stringResource(android.R.string.ok)) AppText(stringResource(android.R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { deleteIndex = null }) { TextButton(onClick = { deleteIndex = null }) {
Text(stringResource(android.R.string.cancel)) AppText(stringResource(android.R.string.cancel))
} }
} }
) )
@@ -22,7 +22,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -38,6 +37,7 @@ import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.data.entities.DictRule import io.legado.app.data.entities.DictRule
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -69,7 +69,7 @@ fun DictRuleEditSheet(
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
CenterAlignedTopAppBar( CenterAlignedTopAppBar(
title = { Text(stringResource(R.string.dict_rule)) }, title = { AppText(stringResource(R.string.dict_rule)) },
navigationIcon = { navigationIcon = {
IconButton(onClick = onDismissRequest) { IconButton(onClick = onDismissRequest) {
Icon( Icon(
@@ -87,7 +87,7 @@ fun DictRuleEditSheet(
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.copy_rule)) }, text = { AppText(stringResource(R.string.copy_rule)) },
leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) }, leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) },
onClick = { onClick = {
onCopy( onCopy(
@@ -102,7 +102,7 @@ fun DictRuleEditSheet(
} }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.paste_rule)) }, text = { AppText(stringResource(R.string.paste_rule)) },
leadingIcon = { Icon(Icons.Default.ContentPaste, null) }, leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
onClick = { onClick = {
scope.launch { scope.launch {
@@ -132,20 +132,20 @@ fun DictRuleEditSheet(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = name, value = name,
onValueChange = { name = it }, onValueChange = { name = it },
label = { Text(stringResource(R.string.name)) }, label = { AppText(stringResource(R.string.name)) },
singleLine = true singleLine = true
) )
OutlinedTextField( OutlinedTextField(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = urlRule, value = urlRule,
onValueChange = { urlRule = it }, onValueChange = { urlRule = it },
label = { Text(stringResource(R.string.url_rule)) } label = { AppText(stringResource(R.string.url_rule)) }
) )
OutlinedTextField( OutlinedTextField(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = showRule, value = showRule,
onValueChange = { showRule = it }, onValueChange = { showRule = it },
label = { Text(stringResource(R.string.show_rule)) }, label = { AppText(stringResource(R.string.show_rule)) },
minLines = 3 minLines = 3
) )
} }
@@ -19,11 +19,9 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -46,6 +44,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseRuleEvent import io.legado.app.base.BaseRuleEvent
import io.legado.app.data.entities.DictRule 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.ActionItem
import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.DraggableSelectionHandler
import io.legado.app.ui.widget.components.button.SmallIconButton 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.RuleEditFields
import io.legado.app.ui.widget.components.rules.RuleEditSheet 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.rules.RuleListScaffold
import io.legado.app.ui.widget.components.text.AppText
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
import sh.calvin.reorderable.rememberReorderableLazyListState import sh.calvin.reorderable.rememberReorderableLazyListState
@@ -195,8 +195,8 @@ fun DictRuleScreen(
onConfirm = { viewModel.saveImportedRules() }, onConfirm = { viewModel.saveImportedRules() },
itemContent = { rule, _ -> itemContent = { rule, _ ->
Column { Column {
Text(rule.name, style = MaterialTheme.typography.titleMedium) AppText(rule.name, style = LegadoTheme.typography.titleMedium)
Text(rule.urlRule, style = MaterialTheme.typography.bodySmall, maxLines = 1) AppText(rule.urlRule, style = LegadoTheme.typography.bodySmall, maxLines = 1)
} }
} }
) )
@@ -211,16 +211,16 @@ fun DictRuleScreen(
showDeleteRuleDialog?.let { rule -> showDeleteRuleDialog?.let { rule ->
AlertDialog( AlertDialog(
onDismissRequest = { showDeleteRuleDialog = null }, onDismissRequest = { showDeleteRuleDialog = null },
title = { Text(stringResource(R.string.delete)) }, title = { AppText(stringResource(R.string.delete)) },
text = { Text(stringResource(R.string.del_msg)) }, text = { AppText(stringResource(R.string.del_msg)) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = { OutlinedButton(onClick = {
viewModel.delete(rule); showDeleteRuleDialog = null viewModel.delete(rule); showDeleteRuleDialog = null
}) { Text(stringResource(R.string.ok)) } }) { AppText(stringResource(R.string.ok)) }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { showDeleteRuleDialog = null }) { TextButton(onClick = { showDeleteRuleDialog = null }) {
Text( AppText(
stringResource(R.string.cancel) stringResource(R.string.cancel)
) )
} }
@@ -310,7 +310,7 @@ fun DictRuleScreen(
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
dropDownMenuContent = { dismiss -> dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_str)) }, text = { AppText(stringResource(R.string.import_str)) },
onClick = { showImportSheet = true; dismiss() }, onClick = { showImportSheet = true; dismiss() },
leadingIcon = { Icon(Icons.Default.FileOpen, null) } leadingIcon = { Icon(Icons.Default.FileOpen, null) }
) )
@@ -181,7 +181,7 @@ open class MainActivity : BaseComposeActivity() {
(slideIntoContainer( (slideIntoContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Start, towards = AnimatedContentTransitionScope.SlideDirection.Start,
animationSpec = tween( animationSpec = tween(
durationMillis = 520, durationMillis = 480,
easing = FastOutSlowInEasing easing = FastOutSlowInEasing
), ),
initialOffset = { fullWidth -> fullWidth } initialOffset = { fullWidth -> fullWidth }
@@ -193,7 +193,7 @@ open class MainActivity : BaseComposeActivity() {
)) togetherWith (slideOutOfContainer( )) togetherWith (slideOutOfContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Start, towards = AnimatedContentTransitionScope.SlideDirection.Start,
animationSpec = tween( animationSpec = tween(
durationMillis = 520, durationMillis = 480,
easing = FastOutSlowInEasing easing = FastOutSlowInEasing
), ),
targetOffset = { fullWidth -> fullWidth / 4 } targetOffset = { fullWidth -> fullWidth / 4 }
@@ -208,7 +208,7 @@ open class MainActivity : BaseComposeActivity() {
(slideIntoContainer( (slideIntoContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Start, towards = AnimatedContentTransitionScope.SlideDirection.Start,
animationSpec = tween( animationSpec = tween(
durationMillis = 520, durationMillis = 480,
easing = FastOutSlowInEasing easing = FastOutSlowInEasing
), ),
initialOffset = { fullWidth -> -fullWidth / 4 } initialOffset = { fullWidth -> -fullWidth / 4 }
@@ -220,7 +220,7 @@ open class MainActivity : BaseComposeActivity() {
)) togetherWith (scaleOut( )) togetherWith (scaleOut(
targetScale = 0.8f, targetScale = 0.8f,
animationSpec = tween( animationSpec = tween(
durationMillis = 520, durationMillis = 480,
easing = FastOutSlowInEasing easing = FastOutSlowInEasing
) )
) + fadeOut( ) + fadeOut(
@@ -12,42 +12,57 @@ import androidx.compose.material.icons.outlined.Person
import androidx.compose.material.icons.outlined.RssFeed import androidx.compose.material.icons.outlined.RssFeed
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import io.legado.app.R 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( sealed class MainDestination(
val route: String, val route: String,
@StringRes val labelId: Int, @StringRes val labelId: Int,
val icon: ImageVector, val m3Icon: ImageVector,
val selectedIcon: ImageVector val m3SelectedIcon: ImageVector,
val miuixIcon: ImageVector,
val miuixSelectedIcon: ImageVector
) { ) {
object Bookshelf : MainDestination( object Bookshelf : MainDestination(
"bookshelf", route = "bookshelf",
R.string.bookshelf, labelId = R.string.bookshelf,
Icons.AutoMirrored.Outlined.LibraryBooks, m3Icon = Icons.AutoMirrored.Outlined.LibraryBooks,
Icons.AutoMirrored.Filled.LibraryBooks m3SelectedIcon = Icons.AutoMirrored.Filled.LibraryBooks,
miuixIcon = MiuixIcons.Regular.ContactsBook, // 替换为实际的 MIUIX 线框图标
miuixSelectedIcon = MiuixIcons.Heavy.ContactsBook // 替换为实际的 MIUIX 填充图标
) )
object Explore : MainDestination( object Explore : MainDestination(
"explore", route = "explore",
R.string.discovery, labelId = R.string.discovery,
Icons.Outlined.Explore, m3Icon = Icons.Outlined.Explore,
Icons.Default.Explore m3SelectedIcon = Icons.Default.Explore,
miuixIcon = MiuixIcons.Regular.Album,
miuixSelectedIcon = MiuixIcons.Heavy.Album
) )
object Rss : MainDestination( object Rss : MainDestination(
"rss", route = "rss",
R.string.rss, labelId = R.string.rss,
Icons.Outlined.RssFeed, m3Icon = Icons.Outlined.RssFeed,
Icons.Default.RssFeed m3SelectedIcon = Icons.Default.RssFeed,
miuixIcon = MiuixIcons.Regular.Favorites,
miuixSelectedIcon = MiuixIcons.Heavy.Favorites
) )
object My : MainDestination( object My : MainDestination(
"my", route = "my",
R.string.my, labelId = R.string.my,
Icons.Outlined.Person, m3Icon = Icons.Outlined.Person,
Icons.Default.Person m3SelectedIcon = Icons.Default.Person,
miuixIcon = MiuixIcons.Regular.Settings,
miuixSelectedIcon = MiuixIcons.Heavy.Settings
) )
companion object { companion object {
val mainDestinations = listOf(Bookshelf, Explore, Rss, My) val mainDestinations = listOf(Bookshelf, Explore, Rss, My)
} }
} }
@@ -20,17 +20,12 @@ import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Badge import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox import androidx.compose.material3.BadgedBox
import androidx.compose.material3.BottomAppBarDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme 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.WideNavigationRail
import androidx.compose.material3.WideNavigationRailItem import androidx.compose.material3.WideNavigationRailItem
import androidx.compose.material3.WideNavigationRailValue 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.info.BookInfoActivity
import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.config.mainConfig.MainConfig 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.BookshelfScreen
import io.legado.app.ui.main.bookshelf.BookshelfViewModel import io.legado.app.ui.main.bookshelf.BookshelfViewModel
import io.legado.app.ui.main.explore.ExploreScreen import io.legado.app.ui.main.explore.ExploreScreen
import io.legado.app.ui.main.my.MyScreen import io.legado.app.ui.main.my.MyScreen
import io.legado.app.ui.main.rss.RssScreen import io.legado.app.ui.main.rss.RssScreen
import io.legado.app.ui.theme.regularHazeEffect 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.AppScaffold
import io.legado.app.ui.widget.components.GlassDefaults 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.RoundDropdownMenu
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem 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.startActivity
import io.legado.app.utils.startActivityForBook import io.legado.app.utils.startActivityForBook
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -151,7 +148,7 @@ fun MainScreen(
onClick = { context.startActivity<SearchActivity>() }, onClick = { context.startActivity<SearchActivity>() },
expanded = expanded, expanded = expanded,
icon = { Icon(Icons.Default.Search, contentDescription = null) }, 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 -> ) { dismiss ->
bookshelfUiState.groups.forEachIndexed { groupIndex, group -> bookshelfUiState.groups.forEachIndexed { groupIndex, group ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(group.groupName) }, text = { AppText(group.groupName) },
onClick = { onClick = {
coroutineScope.launch { coroutineScope.launch {
if (pagerState.currentPage != index) { if (pagerState.currentPage != index) {
@@ -224,7 +221,7 @@ fun MainScreen(
} }
}, },
label = if (labelVisibilityMode != "unlabeled") { label = if (labelVisibilityMode != "unlabeled") {
{ Text(stringResource(destination.labelId)) } { AppText(stringResource(destination.labelId)) }
} else null } else null
) )
} }
@@ -237,103 +234,34 @@ fun MainScreen(
if (!useRail && MainConfig.showBottomView) { if (!useRail && MainConfig.showBottomView) {
val labelVisibilityMode = MainConfig.labelVisibilityMode val labelVisibilityMode = MainConfig.labelVisibilityMode
val isUnlabeled = labelVisibilityMode == "unlabeled" val isUnlabeled = labelVisibilityMode == "unlabeled"
NavigationBar(
AppNavigationBar(
modifier = Modifier modifier = Modifier
.regularHazeEffect(state = hazeState) .regularHazeEffect(state = hazeState)
.height(if (isUnlabeled) 64.dp else 80.dp), .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))
}
) { ) {
val alwaysShowLabel = when (labelVisibilityMode) { val alwaysShowLabel = when (labelVisibilityMode) {
"labeled" -> true "labeled" -> true
"selected" -> false
"unlabeled" -> false
else -> false else -> false
} }
destinations.forEachIndexed { index, destination -> destinations.forEachIndexed { index, destination ->
val selected = pagerState.targetPage == index val selected = pagerState.targetPage == index
var showGroupMenu by remember { mutableStateOf(false) } AppNavigationBarItem(
val haptic = LocalHapticFeedback.current
NavigationBarItem(
selected = selected, selected = selected,
onClick = { onClick = {
coroutineScope.launch { coroutineScope.launch { pagerState.animateScrollToPage(index) }
pagerState.animateScrollToPage(index)
}
}, },
icon = { labelString = stringResource(destination.labelId),
Box { miuixIcon = if (selected) destination.miuixSelectedIcon else destination.miuixIcon,
NavigationIcon( m3Icon = {
destination = destination, if (selected) destination.m3SelectedIcon else destination.m3Icon
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)
)
}
}
)
}
}
}
}
}, },
colors = NavigationBarItemDefaults.colors( m3IndicatorColor = GlassDefaults.glassColor(
indicatorColor = GlassDefaults.glassColor( noBlurColor = MaterialTheme.colorScheme.secondaryContainer,
noBlurColor = MaterialTheme.colorScheme.secondaryContainer, blurAlpha = GlassDefaults.ThickBlurAlpha
blurAlpha = GlassDefaults.ThickBlurAlpha
),
), ),
label = if (labelVisibilityMode != "unlabeled") { m3ShowLabel = !isUnlabeled,
{ Text(stringResource(destination.labelId)) } m3AlwaysShowLabel = alwaysShowLabel
} else null,
alwaysShowLabel = alwaysShowLabel
) )
} }
} }
@@ -386,10 +314,10 @@ private fun NavigationIcon(
upBooksCount: Int, upBooksCount: Int,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val icon = if (selected) destination.selectedIcon else destination.icon val icon = if (selected) destination.m3SelectedIcon else destination.m3Icon
Box(modifier = modifier) { Box(modifier = modifier) {
if (destination == MainDestination.Bookshelf && upBooksCount > 0) { if (destination == MainDestination.Bookshelf && upBooksCount > 0) {
BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) { BadgedBox(badge = { Badge { AppText(upBooksCount.toString()) } }) {
Icon(icon, contentDescription = null) Icon(icon, contentDescription = null)
} }
} else { } else {
@@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -34,9 +33,11 @@ import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.data.entities.BookGroup import io.legado.app.data.entities.BookGroup
import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig 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.BookCover
import io.legado.app.ui.widget.components.cover.BookshelfCover 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.cover.Cover
import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.utils.toTimeAgo import io.legado.app.utils.toTimeAgo
/** /**
@@ -88,9 +89,9 @@ fun BookshelfItem(
) { ) {
cover(Modifier.fillMaxSize()) cover(Modifier.fillMaxSize())
if (gridStyle == 1) { if (gridStyle == 1) {
Text( AppText(
text = title, 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, color = Color.White,
shadow = Shadow( shadow = Shadow(
color = Color.Black.copy(alpha = 0.5f), color = Color.Black.copy(alpha = 0.5f),
@@ -117,9 +118,9 @@ fun BookshelfItem(
} }
if (gridStyle == 0) { if (gridStyle == 0) {
Text( AppText(
text = title, text = title,
style = if (titleSmallFont) MaterialTheme.typography.labelSmall else MaterialTheme.typography.labelMedium, style = if (titleSmallFont) LegadoTheme.typography.labelSmall else LegadoTheme.typography.labelMedium,
maxLines = titleMaxLines, maxLines = titleMaxLines,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
textAlign = if (titleCenter) TextAlign.Center else TextAlign.Start, textAlign = if (titleCenter) TextAlign.Center else TextAlign.Start,
@@ -152,16 +153,16 @@ fun BookshelfItem(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
Text( AppText(
text = title, text = title,
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold), style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold),
maxLines = if (!isCompact) 2 else 1, maxLines = if (!isCompact) 2 else 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
subTitle?.let { subTitle?.let {
Text( AppText(
text = it, text = it,
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(top = 2.dp) modifier = Modifier.padding(top = 2.dp)
@@ -169,9 +170,9 @@ fun BookshelfItem(
} }
if (!isCompact) { if (!isCompact) {
desc?.let { desc?.let {
Text( AppText(
text = it, text = it,
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(top = 2.dp) modifier = Modifier.padding(top = 2.dp)
@@ -372,7 +373,7 @@ fun BookItem(
isUpdating = isUpdating, isUpdating = isUpdating,
modifier = modifier, modifier = modifier,
badgeText = if (BookshelfConfig.showUnread && unreadCount > 0) unreadCount.toString() else null, 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, title = book.name,
@@ -384,16 +385,16 @@ fun BookItem(
desc = stringResource(R.string.read_dur_progress, book.durChapterTitle ?: ""), desc = stringResource(R.string.read_dur_progress, book.durChapterTitle ?: ""),
extra = { extra = {
if (BookshelfConfig.showLastUpdateTime && !book.isLocal) { if (BookshelfConfig.showLastUpdateTime && !book.isLocal) {
Text( AppText(
text = book.latestChapterTime.toTimeAgo(), text = book.latestChapterTime.toTimeAgo(),
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = if (layoutMode != 0 || !isCompact) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary, color = if (layoutMode != 0 || !isCompact) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary,
modifier = Modifier.padding(end = 4.dp) modifier = Modifier.padding(end = 4.dp)
) )
} }
Text( AppText(
text = book.latestChapterTitle ?: "", text = book.latestChapterTitle ?: "",
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
@@ -16,6 +16,7 @@ data class BookShelfItem(
val durChapterPos: Int, val durChapterPos: Int,
val latestChapterTitle: String?, val latestChapterTitle: String?,
val latestChapterTime: Long, val latestChapterTime: Long,
val lastCheckCount: Int,
val totalChapterNum: Int, val totalChapterNum: Int,
val durChapterIndex: Int, val durChapterIndex: Int,
val type: Int, val type: Int,
@@ -33,5 +34,8 @@ data class BookShelfItem(
val isNotShelf: Boolean get() = (type and BookType.notShelf) > 0 val isNotShelf: Boolean get() = (type and BookType.notShelf) > 0
val isNew: Boolean get() = lastCheckCount > 0
fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0) fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0)
} }
@@ -23,7 +23,6 @@ import androidx.compose.material.icons.filled.TextFormat
import androidx.compose.material.icons.filled.ViewCompact import androidx.compose.material.icons.filled.ViewCompact
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
@@ -32,10 +31,12 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig 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.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem 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.CompactSliderSettingItem
import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -55,9 +56,9 @@ fun BookshelfConfigSheet(
.padding(bottom = 32.dp), .padding(bottom = 32.dp),
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
Text( AppText(
text = stringResource(R.string.bookshelf_layout), text = stringResource(R.string.bookshelf_layout),
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
modifier = Modifier.padding(vertical = 16.dp) modifier = Modifier.padding(vertical = 16.dp)
) )
@@ -45,7 +45,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Tab 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.PullToRefreshDefaults
import androidx.compose.material3.pulltorefresh.pullToRefresh import androidx.compose.material3.pulltorefresh.pullToRefresh
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState 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.manage.BookshelfManageActivity
import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig 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.button.SmallOutlinedIconToggleButton
import io.legado.app.ui.widget.components.filePicker.FilePickerSheet import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
import io.legado.app.ui.widget.components.importComponents.SourceInputDialog 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.list.ListScaffold
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu 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.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.tabRow.AdaptiveTabRow
import io.legado.app.utils.readText import io.legado.app.utils.readText
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
@@ -235,37 +237,37 @@ fun BookshelfScreen(
topBarActions = { }, topBarActions = { },
dropDownMenuContent = { dismiss -> dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.add_remote_book)) }, text = { AppText(stringResource(R.string.add_remote_book)) },
onClick = { context.startActivity<RemoteBookActivity>(); dismiss() }, onClick = { context.startActivity<RemoteBookActivity>(); dismiss() },
leadingIcon = { Icon(Icons.Default.Wifi, null) } leadingIcon = { Icon(Icons.Default.Wifi, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.book_local)) }, text = { AppText(stringResource(R.string.book_local)) },
onClick = { context.startActivity<ImportBookActivity>(); dismiss() }, onClick = { context.startActivity<ImportBookActivity>(); dismiss() },
leadingIcon = { Icon(Icons.Default.Save, null) } leadingIcon = { Icon(Icons.Default.Save, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.update_toc)) }, text = { AppText(stringResource(R.string.update_toc)) },
onClick = { viewModel.upToc(uiState.items); dismiss() }, onClick = { viewModel.upToc(uiState.items); dismiss() },
leadingIcon = { Icon(Icons.Default.Refresh, null) } leadingIcon = { Icon(Icons.Default.Refresh, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("布局设置") }, text = { AppText("布局设置") },
onClick = { showConfigSheet = true; dismiss() }, onClick = { showConfigSheet = true; dismiss() },
leadingIcon = { Icon(Icons.Default.GridView, null) } leadingIcon = { Icon(Icons.Default.GridView, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.group_manage)) }, text = { AppText(stringResource(R.string.group_manage)) },
onClick = { showGroupManageSheet = true; dismiss() }, onClick = { showGroupManageSheet = true; dismiss() },
leadingIcon = { Icon(Icons.Default.Edit, null) } leadingIcon = { Icon(Icons.Default.Edit, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.add_url)) }, text = { AppText(stringResource(R.string.add_url)) },
onClick = { showAddUrlDialog = true; dismiss() }, onClick = { showAddUrlDialog = true; dismiss() },
leadingIcon = { Icon(Icons.Default.Link, null) } leadingIcon = { Icon(Icons.Default.Link, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.bookshelf_management)) }, text = { AppText(stringResource(R.string.bookshelf_management)) },
onClick = { onClick = {
val groupId = val groupId =
uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L
@@ -277,7 +279,7 @@ fun BookshelfScreen(
leadingIcon = { Icon(Icons.Default.Settings, null) } leadingIcon = { Icon(Icons.Default.Settings, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.cache_export)) }, text = { AppText(stringResource(R.string.cache_export)) },
onClick = { onClick = {
val groupId = val groupId =
uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L
@@ -289,7 +291,7 @@ fun BookshelfScreen(
leadingIcon = { Icon(Icons.Default.Download, null) } leadingIcon = { Icon(Icons.Default.Download, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.export_bookshelf)) }, text = { AppText(stringResource(R.string.export_bookshelf)) },
onClick = { onClick = {
showExportSheet = true showExportSheet = true
dismiss() dismiss()
@@ -297,12 +299,12 @@ fun BookshelfScreen(
leadingIcon = { Icon(Icons.Default.ImportExport, null) } leadingIcon = { Icon(Icons.Default.ImportExport, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_bookshelf)) }, text = { AppText(stringResource(R.string.import_bookshelf)) },
onClick = { showImportSheet = true; dismiss() }, onClick = { showImportSheet = true; dismiss() },
leadingIcon = { Icon(Icons.Default.FileOpen, null) } leadingIcon = { Icon(Icons.Default.FileOpen, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.log)) }, text = { AppText(stringResource(R.string.log)) },
onClick = { onClick = {
showLogSheet = true showLogSheet = true
dismiss() dismiss()
@@ -320,33 +322,19 @@ fun BookshelfScreen(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
PrimaryScrollableTabRow( val tabTitles = remember(uiState.groups) {
selectedTabIndex = selectedTabIndex, uiState.groups.map { it.groupName }
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
)
}
)
}
} }
AdaptiveTabRow(
tabTitles = tabTitles,
selectedTabIndex = selectedTabIndex,
onTabSelected = { index ->
scope.launch { pagerState.animateScrollToPage(index) }
},
modifier = Modifier.weight(1f)
)
if (BookshelfConfig.shouldShowExpandButton) { if (BookshelfConfig.shouldShowExpandButton) {
Box(modifier = Modifier.padding(end = 16.dp)) { Box(modifier = Modifier.padding(end = 16.dp)) {
SmallOutlinedIconToggleButton( SmallOutlinedIconToggleButton(
@@ -361,7 +349,7 @@ fun BookshelfScreen(
) { dismiss -> ) { dismiss ->
uiState.groups.forEachIndexed { index, group -> uiState.groups.forEachIndexed { index, group ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(group.groupName) }, text = { AppText(group.groupName) },
onClick = { onClick = {
scope.launch { pagerState.animateScrollToPage(index) } scope.launch { pagerState.animateScrollToPage(index) }
dismiss() dismiss()
@@ -565,10 +553,10 @@ fun BookshelfScreen(
) { ) {
CircularProgressIndicator() CircularProgressIndicator()
uiState.loadingText?.let { uiState.loadingText?.let {
Text( AppText(
text = it, text = it,
modifier = Modifier.padding(top = 16.dp), modifier = Modifier.padding(top = 16.dp),
style = MaterialTheme.typography.bodyMedium style = LegadoTheme.typography.bodyMedium
) )
} }
} }
@@ -19,7 +19,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState 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.data.entities.BookGroup
import io.legado.app.ui.book.group.GroupEditContent import io.legado.app.ui.book.group.GroupEditContent
import io.legado.app.ui.book.group.GroupViewModel 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.card.ReorderableSelectionItem
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet 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 io.legado.app.utils.move
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
import sh.calvin.reorderable.rememberReorderableLazyListState import sh.calvin.reorderable.rememberReorderableLazyListState
@@ -104,9 +105,9 @@ fun GroupManageSheet(
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text( AppText(
text = stringResource(R.string.group_manage), text = stringResource(R.string.group_manage),
style = MaterialTheme.typography.titleLarge style = LegadoTheme.typography.titleLarge
) )
IconButton(onClick = { IconButton(onClick = {
editingGroup = null editingGroup = null
@@ -43,7 +43,6 @@ import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider 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.search.SearchScope
import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.book.source.edit.BookSourceEditActivity
import io.legado.app.ui.login.SourceLoginActivity 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.GlassCard
import io.legado.app.ui.widget.components.card.TextCard import io.legado.app.ui.widget.components.card.TextCard
import io.legado.app.ui.widget.components.divider.PillHeaderDivider 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.MenuItemIcon
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu 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.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
import top.yukonga.miuix.kmp.theme.MiuixTheme
import kotlin.math.roundToInt import kotlin.math.roundToInt
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@@ -148,13 +152,13 @@ fun ExploreScreen(
dropDownMenuContent = { dismiss -> dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.Group) }, leadingIcon = { MenuItemIcon(Icons.Default.Group) },
text = { Text(stringResource(R.string.all)) }, text = { AppText(stringResource(R.string.all)) },
onClick = { viewModel.setGroup(""); dismiss() } onClick = { viewModel.setGroup(""); dismiss() }
) )
uiState.groups.forEach { group -> uiState.groups.forEach { group ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) }, leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) },
text = { Text(group) }, text = { AppText(group) },
onClick = { viewModel.setGroup(group); dismiss() } onClick = { viewModel.setGroup(group); dismiss() }
) )
} }
@@ -274,19 +278,19 @@ fun ExploreScreen(
sourceToDelete?.let { source -> sourceToDelete?.let { source ->
AlertDialog( AlertDialog(
onDismissRequest = { sourceToDelete = null }, onDismissRequest = { sourceToDelete = null },
title = { Text(stringResource(R.string.draw)) }, title = { AppText(stringResource(R.string.draw)) },
text = { Text(stringResource(R.string.sure_del) + "\n" + source.bookSourceName) }, text = { AppText(stringResource(R.string.sure_del) + "\n" + source.bookSourceName) },
confirmButton = { confirmButton = {
TextButton(onClick = { TextButton(onClick = {
viewModel.deleteSource(source) viewModel.deleteSource(source)
sourceToDelete = null sourceToDelete = null
}) { }) {
Text(stringResource(R.string.yes)) AppText(stringResource(R.string.yes))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { sourceToDelete = null }) { 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) } var showMenu by remember { mutableStateOf(false) }
val rotation by animateFloatAsState(if (isExpanded) 90f else 0f, label = "rotation") val rotation by animateFloatAsState(if (isExpanded) 90f else 0f, label = "rotation")
val composeEngine = ThemeResolver.isMiuixEngine(composeEngine)
val containerColor by animateColorAsState( val containerColor by animateColorAsState(
targetValue = if (isExpanded) targetValue = if (isExpanded)
MaterialTheme.colorScheme.secondaryContainer if (composeEngine) MiuixTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.secondaryContainer
else 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), animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing),
label = "CardColor" label = "CardColor"
) )
@@ -358,7 +373,7 @@ fun ExploreSourceHeader(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 4.dp), .padding(horizontal = 16.dp, vertical = 4.dp),
shape = MaterialTheme.shapes.medium, shape = MaterialTheme.shapes.medium,
colors = CardDefaults.cardColors(containerColor = containerColor), containerColor = containerColor
) { ) {
ListItem( ListItem(
modifier = Modifier modifier = Modifier
@@ -371,14 +386,10 @@ fun ExploreSourceHeader(
containerColor = Color.Transparent containerColor = Color.Transparent
), ),
headlineContent = { headlineContent = {
Text( AppText(
text = item.bookSourceName, text = item.bookSourceName,
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
color = if (isExpanded) { color = contentColor
MaterialTheme.colorScheme.primary
} else {
MaterialTheme.colorScheme.onSurface
}
) )
}, },
trailingContent = { trailingContent = {
@@ -401,29 +412,29 @@ fun ExploreSourceHeader(
PillHeaderDivider(title = item.bookSourceName) PillHeaderDivider(title = item.bookSourceName)
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) }, leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) },
text = { Text(stringResource(R.string.to_top)) }, text = { AppText(stringResource(R.string.to_top)) },
onClick = { onTop(); showMenu = false } onClick = { onTop(); showMenu = false }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.Edit) }, leadingIcon = { MenuItemIcon(Icons.Default.Edit) },
text = { Text(stringResource(R.string.edit)) }, text = { AppText(stringResource(R.string.edit)) },
onClick = { onEdit(); showMenu = false } onClick = { onEdit(); showMenu = false }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.Search) }, leadingIcon = { MenuItemIcon(Icons.Default.Search) },
text = { Text(stringResource(R.string.search)) }, text = { AppText(stringResource(R.string.search)) },
onClick = { onSearch(); showMenu = false } onClick = { onSearch(); showMenu = false }
) )
if (item.hasLoginUrl) { if (item.hasLoginUrl) {
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) }, leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) },
text = { Text(stringResource(R.string.login)) }, text = { AppText(stringResource(R.string.login)) },
onClick = { onLogin(); showMenu = false } onClick = { onLogin(); showMenu = false }
) )
} }
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.Refresh) }, leadingIcon = { MenuItemIcon(Icons.Default.Refresh) },
text = { Text(stringResource(R.string.refresh)) }, text = { AppText(stringResource(R.string.refresh)) },
onClick = { onRefresh(); showMenu = false } onClick = { onRefresh(); showMenu = false }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
@@ -434,7 +445,7 @@ fun ExploreSourceHeader(
) )
}, },
text = { text = {
Text( AppText(
stringResource(R.string.delete), stringResource(R.string.delete),
color = MaterialTheme.colorScheme.error color = MaterialTheme.colorScheme.error
) )
@@ -455,7 +466,7 @@ fun ExploreStickyCard(
TextCard( TextCard(
text = item.bookSourceName, text = item.bookSourceName,
backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh, backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh,
textStyle = MaterialTheme.typography.labelLarge, textStyle = LegadoTheme.typography.labelLarge,
horizontalPadding = 8.dp, horizontalPadding = 8.dp,
verticalPadding = 6.dp, verticalPadding = 6.dp,
onClick = onClick onClick = onClick
@@ -479,10 +490,8 @@ fun ExploreKindItem(
GlassCard( GlassCard(
onClick = onClick, onClick = onClick,
shape = shape, shape = shape,
colors = CardDefaults.cardColors( containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.6f),
containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.6f), contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
),
modifier = modifier modifier = modifier
) { ) {
KindText(kind) KindText(kind)
@@ -506,12 +515,12 @@ fun ExploreKindItem(
private fun KindText( private fun KindText(
kind: ExploreKind kind: ExploreKind
) { ) {
Text( AppText(
text = kind.title, text = kind.title,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 8.dp), .padding(vertical = 8.dp),
style = MaterialTheme.typography.labelMediumEmphasized, style = LegadoTheme.typography.labelMediumEmphasized,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
maxLines = 1 maxLines = 1
@@ -1,13 +1,20 @@
package io.legado.app.ui.main.my 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.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons 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.LibraryBooks
import androidx.compose.material.icons.automirrored.filled.Rule import androidx.compose.material.icons.automirrored.filled.Rule
import androidx.compose.material.icons.filled.Bookmark 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.FindReplace
import androidx.compose.material.icons.filled.Folder import androidx.compose.material.icons.filled.Folder
import androidx.compose.material.icons.filled.History import androidx.compose.material.icons.filled.History
import androidx.compose.material.icons.filled.Info 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.Settings
import androidx.compose.material.icons.filled.Source import androidx.compose.material.icons.filled.Source
import androidx.compose.material.icons.filled.Web import androidx.compose.material.icons.filled.Web
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue 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.dict.rule.DictRuleActivity
import io.legado.app.ui.file.FileManageActivity import io.legado.app.ui.file.FileManageActivity
import io.legado.app.ui.replace.ReplaceRuleActivity 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.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.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) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@@ -70,11 +79,7 @@ fun MyScreen(
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top), .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { title = stringResource(R.string.my),
Text(
text = stringResource(R.string.my)
)
},
actions = { actions = {
IconButton( IconButton(
onClick = { onNavigate(PrefClickEvent.ShowMd("appHelp", "xxx")) } onClick = { onNavigate(PrefClickEvent.ShowMd("appHelp", "xxx")) }
@@ -99,52 +104,21 @@ fun MyScreen(
) )
SplicedColumnGroup( SplicedColumnGroup(
modifier = Modifier.padding(horizontal = 16.dp), modifier = Modifier.adaptiveHorizontalPadding(),
title = "" title = ""
) { ) {
SettingItem( WebServiceSettingBlock(
title = stringResource(R.string.web_service), uiState = uiState,
description = if (uiState.isWebServiceRun) viewModel = viewModel,
uiState.webServiceAddress onNavigate = onNavigate
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 = { }
) )
} }
SplicedColumnGroup( SplicedColumnGroup(
modifier = Modifier.padding(horizontal = 16.dp), modifier = Modifier.adaptiveHorizontalPadding(),
title = "规则" title = "规则"
) { ) {
SettingItem( ClickableSettingItem(
title = stringResource(R.string.book_source_manage), title = stringResource(R.string.book_source_manage),
description = stringResource(R.string.book_source_manage_desc), description = stringResource(R.string.book_source_manage_desc),
imageVector = Icons.Default.Source, imageVector = Icons.Default.Source,
@@ -154,7 +128,7 @@ fun MyScreen(
) )
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.replace_purify), title = stringResource(R.string.replace_purify),
imageVector = Icons.Default.FindReplace, imageVector = Icons.Default.FindReplace,
onClick = { onClick = {
@@ -163,7 +137,7 @@ fun MyScreen(
) )
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.txt_toc_rule), title = stringResource(R.string.txt_toc_rule),
imageVector = Icons.AutoMirrored.Filled.Rule, imageVector = Icons.AutoMirrored.Filled.Rule,
onClick = { onClick = {
@@ -172,7 +146,7 @@ fun MyScreen(
) )
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.dict_rule), title = stringResource(R.string.dict_rule),
imageVector = Icons.AutoMirrored.Filled.LibraryBooks, imageVector = Icons.AutoMirrored.Filled.LibraryBooks,
onClick = { onClick = {
@@ -184,44 +158,44 @@ fun MyScreen(
} }
SplicedColumnGroup( SplicedColumnGroup(
modifier = Modifier.padding(horizontal = 16.dp), modifier = Modifier.adaptiveHorizontalPadding(),
title = stringResource(R.string.other)) { title = stringResource(R.string.other)) {
SettingItem( ClickableSettingItem(
title = stringResource(R.string.setting), title = stringResource(R.string.setting),
imageVector = Icons.Default.Settings, imageVector = Icons.Default.Settings,
onClick = { onClick = {
onOpenSettings() onOpenSettings()
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.bookmark), title = stringResource(R.string.bookmark),
imageVector = Icons.Default.Bookmark, imageVector = Icons.Default.Bookmark,
onClick = { onClick = {
onNavigate(PrefClickEvent.StartActivity(AllBookmarkActivity::class.java)) onNavigate(PrefClickEvent.StartActivity(AllBookmarkActivity::class.java))
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.read_record), title = stringResource(R.string.read_record),
imageVector = Icons.Default.History, imageVector = Icons.Default.History,
onClick = { onClick = {
onNavigate(PrefClickEvent.StartActivity(ReadRecordActivity::class.java)) onNavigate(PrefClickEvent.StartActivity(ReadRecordActivity::class.java))
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.file_manage), title = stringResource(R.string.file_manage),
imageVector = Icons.Default.Folder, imageVector = Icons.Default.Folder,
onClick = { onClick = {
onNavigate(PrefClickEvent.StartActivity(FileManageActivity::class.java)) onNavigate(PrefClickEvent.StartActivity(FileManageActivity::class.java))
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.about), title = stringResource(R.string.about),
imageVector = Icons.Default.Info, imageVector = Icons.Default.Info,
onClick = { onClick = {
onNavigate(PrefClickEvent.StartActivity(AboutActivity::class.java)) onNavigate(PrefClickEvent.StartActivity(AboutActivity::class.java))
} }
) )
SettingItem( ClickableSettingItem(
title = stringResource(R.string.exit), title = stringResource(R.string.exit),
imageVector = Icons.AutoMirrored.Filled.ExitToApp, imageVector = Icons.AutoMirrored.Filled.ExitToApp,
onClick = { 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))
}
)
}
}
}
}
@@ -30,7 +30,6 @@ import androidx.compose.material.icons.filled.VerticalAlignTop
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState 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.edit.RssSourceEditActivity
import io.legado.app.ui.rss.source.manage.RssSourceActivity import io.legado.app.ui.rss.source.manage.RssSourceActivity
import io.legado.app.ui.rss.subscription.RuleSubActivity 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.SourceIcon
import io.legado.app.ui.widget.components.button.TopBarActionButton import io.legado.app.ui.widget.components.button.TopBarActionButton
import io.legado.app.ui.widget.components.divider.PillDivider 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.MenuItemIcon
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu 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.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.utils.openUrl import io.legado.app.utils.openUrl
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -135,12 +136,12 @@ fun RssScreen(
dismiss() dismiss()
}, },
leadingIcon = { MenuItemIcon(Icons.Default.Settings) }, leadingIcon = { MenuItemIcon(Icons.Default.Settings) },
text = { Text("订阅源管理") } text = { AppText("订阅源管理") }
) )
PillDivider() PillDivider()
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.Group) }, leadingIcon = { MenuItemIcon(Icons.Default.Group) },
text = { Text(stringResource(R.string.all)) }, text = { AppText(stringResource(R.string.all)) },
onClick = { onClick = {
viewModel.setGroup("") viewModel.setGroup("")
dismiss() dismiss()
@@ -149,7 +150,7 @@ fun RssScreen(
uiState.groups.forEach { group -> uiState.groups.forEach { group ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) }, leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) },
text = { Text(group) }, text = { AppText(group) },
onClick = { onClick = {
viewModel.setGroup(group) viewModel.setGroup(group)
dismiss() dismiss()
@@ -188,8 +189,8 @@ fun RssScreen(
sourceToDelete?.let { source -> sourceToDelete?.let { source ->
AlertDialog( AlertDialog(
onDismissRequest = { sourceToDelete = null }, onDismissRequest = { sourceToDelete = null },
title = { Text(stringResource(R.string.draw)) }, title = { AppText(stringResource(R.string.draw)) },
text = { Text(stringResource(R.string.sure_del) + "\n" + source.sourceName) }, text = { AppText(stringResource(R.string.sure_del) + "\n" + source.sourceName) },
confirmButton = { confirmButton = {
TextButton( TextButton(
onClick = { onClick = {
@@ -197,12 +198,12 @@ fun RssScreen(
sourceToDelete = null sourceToDelete = null
} }
) { ) {
Text(stringResource(R.string.yes)) AppText(stringResource(R.string.yes))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { sourceToDelete = null }) { TextButton(onClick = { sourceToDelete = null }) {
Text(stringResource(R.string.no)) AppText(stringResource(R.string.no))
} }
} }
) )
@@ -246,7 +247,7 @@ fun RssSourceGridItem(
PillHeaderDivider(title = source.sourceName) PillHeaderDivider(title = source.sourceName)
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) }, leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) },
text = { Text(stringResource(R.string.to_top)) }, text = { AppText(stringResource(R.string.to_top)) },
onClick = { onClick = {
onTop() onTop()
showMenu = false showMenu = false
@@ -254,7 +255,7 @@ fun RssSourceGridItem(
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.Edit) }, leadingIcon = { MenuItemIcon(Icons.Default.Edit) },
text = { Text(stringResource(R.string.edit)) }, text = { AppText(stringResource(R.string.edit)) },
onClick = { onClick = {
onEdit() onEdit()
showMenu = false showMenu = false
@@ -263,7 +264,7 @@ fun RssSourceGridItem(
if (!source.loginUrl.isNullOrBlank()) { if (!source.loginUrl.isNullOrBlank()) {
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) }, leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) },
text = { Text(stringResource(R.string.login)) }, text = { AppText(stringResource(R.string.login)) },
onClick = { onClick = {
onLogin() onLogin()
showMenu = false showMenu = false
@@ -272,7 +273,7 @@ fun RssSourceGridItem(
} }
RoundDropdownMenuItem( RoundDropdownMenuItem(
leadingIcon = { MenuItemIcon(Icons.Default.Close) }, leadingIcon = { MenuItemIcon(Icons.Default.Close) },
text = { Text(stringResource(R.string.disable_source)) }, text = { AppText(stringResource(R.string.disable_source)) },
onClick = { onClick = {
onDisable() onDisable()
showMenu = false showMenu = false
@@ -286,7 +287,7 @@ fun RssSourceGridItem(
) )
}, },
text = { text = {
Text( AppText(
stringResource(R.string.delete), stringResource(R.string.delete),
color = MaterialTheme.colorScheme.error color = MaterialTheme.colorScheme.error
) )
@@ -299,9 +300,9 @@ fun RssSourceGridItem(
} }
} }
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( AppText(
text = source.sourceName, text = source.sourceName,
style = MaterialTheme.typography.labelMedium, style = LegadoTheme.typography.labelMedium,
maxLines = 2, maxLines = 2,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
@@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
@@ -26,14 +25,10 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.LoadingIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.PlainTooltip import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.PrimaryScrollableTabRow
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TooltipAnchorPosition import androidx.compose.material3.TooltipAnchorPosition
import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipBox
@@ -50,20 +45,19 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseRuleEvent import io.legado.app.base.BaseRuleEvent
import io.legado.app.data.entities.ReplaceRule 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.ActionItem
import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.DraggableSelectionHandler
import io.legado.app.ui.widget.components.GroupManageBottomSheet 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.lazylist.FastScrollLazyColumn
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem 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.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 kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
import sh.calvin.reorderable.rememberReorderableLazyListState import sh.calvin.reorderable.rememberReorderableLazyListState
@@ -207,9 +203,9 @@ fun ReplaceRuleScreen(
topBarActions = {}, topBarActions = {},
itemContent = { rule, _ -> itemContent = { rule, _ ->
Column { Column {
Text(rule.name, style = MaterialTheme.typography.titleMedium) AppText(rule.name, style = LegadoTheme.typography.titleMedium)
if (!rule.group.isNullOrBlank()) { 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 -> showDeleteRuleDialog?.let { rule ->
AlertDialog( AlertDialog(
onDismissRequest = { showDeleteRuleDialog = null }, onDismissRequest = { showDeleteRuleDialog = null },
title = { Text(stringResource(R.string.delete)) }, title = { AppText(stringResource(R.string.delete)) },
text = { Text(stringResource(R.string.del_msg)) }, text = { AppText(stringResource(R.string.del_msg)) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = { OutlinedButton(onClick = {
viewModel.delete(rule); showDeleteRuleDialog = null viewModel.delete(rule); showDeleteRuleDialog = null
}) { Text(stringResource(R.string.ok)) } }) { AppText(stringResource(R.string.ok)) }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { showDeleteRuleDialog = null }) { TextButton(onClick = { showDeleteRuleDialog = null }) {
Text( AppText(
stringResource(R.string.cancel) stringResource(R.string.cancel)
) )
} }
@@ -347,39 +343,21 @@ fun ReplaceRuleScreen(
}, },
bottomContent = { bottomContent = {
if (tabItems.size > 1) { if (tabItems.size > 1) {
PrimaryScrollableTabRow( AdaptiveTabRow(
selectedTabIndex = selectedTabIndex.coerceAtMost(tabItems.size - 1) tabTitles = tabItems,
.coerceAtLeast(0), selectedTabIndex = selectedTabIndex,
edgePadding = 0.dp, onTabSelected = { index ->
divider = {}, selectedTabIndex = index
containerColor = Color.Transparent, viewModel.setGroup(tabItems[index])
) {
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
)
}
)
} }
} )
} }
}, },
floatingActionButton = { floatingActionButton = {
TooltipBox( TooltipBox(
positionProvider = positionProvider =
TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above), TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = { PlainTooltip { Text("Localized description") } }, tooltip = { PlainTooltip { AppText("Localized description") } },
state = rememberTooltipState(), state = rememberTooltipState(),
) { ) {
with(sharedTransitionScope) { with(sharedTransitionScope) {
@@ -406,29 +384,29 @@ fun ReplaceRuleScreen(
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
dropDownMenuContent = { dismiss -> dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_str)) }, text = { AppText(stringResource(R.string.import_str)) },
onClick = { showImportSheet = true; dismiss() }, onClick = { showImportSheet = true; dismiss() },
leadingIcon = { Icon(Icons.Default.FileOpen, null) } leadingIcon = { Icon(Icons.Default.FileOpen, null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("分组管理") }, text = { AppText("分组管理") },
onClick = { showGroupManageSheet = true; dismiss() } onClick = { showGroupManageSheet = true; dismiss() }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("帮助") }, text = { AppText("帮助") },
onClick = { /*TODO*/ dismiss() } onClick = { /*TODO*/ dismiss() }
) )
PillDivider() PillDivider()
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("旧的在前") }, text = { AppText("旧的在前") },
onClick = { viewModel.setSortMode("asc"); dismiss() } onClick = { viewModel.setSortMode("asc"); dismiss() }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("新的在前") }, text = { AppText("新的在前") },
onClick = { viewModel.setSortMode("desc"); dismiss() } onClick = { viewModel.setSortMode("desc"); dismiss() }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("名称升序") }, text = { AppText("名称升序") },
onClick = { onClick = {
viewModel.setSortMode("name_asc") viewModel.setSortMode("name_asc")
dismiss() dismiss()
@@ -438,7 +416,7 @@ fun ReplaceRuleScreen(
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text("名称降序") }, text = { AppText("名称降序") },
onClick = { onClick = {
viewModel.setSortMode("name_desc") viewModel.setSortMode("name_desc")
dismiss() dismiss()
@@ -496,15 +474,15 @@ fun ReplaceRuleScreen(
), ),
dropdownContent = { dismiss -> dropdownContent = { dismiss ->
DropdownMenuItem( DropdownMenuItem(
text = { Text("移至顶部") }, text = { AppText("移至顶部") },
onClick = { viewModel.toTop(ui.rule); dismiss() } onClick = { viewModel.toTop(ui.rule); dismiss() }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text("移至底部") }, text = { AppText("移至底部") },
onClick = { viewModel.toBottom(ui.rule); dismiss() } onClick = { viewModel.toBottom(ui.rule); dismiss() }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text("删除") }, text = { AppText("删除") },
onClick = { showDeleteRuleDialog = ui.rule; dismiss() } onClick = { showDeleteRuleDialog = ui.rule; dismiss() }
) )
} }
@@ -52,7 +52,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.PlainTooltip import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TooltipAnchorPosition import androidx.compose.material3.TooltipAnchorPosition
import androidx.compose.material3.TooltipBox 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.unit.dp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import io.legado.app.ui.widget.components.AppScaffold 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.AlertButton
import io.legado.app.ui.widget.components.button.TopbarNavigationButton 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 import org.koin.androidx.compose.koinViewModel
@Composable @Composable
@@ -119,7 +119,7 @@ fun ReplaceEditScreen(
.imePadding(), .imePadding(),
topBar = { topBar = {
GlassMediumFlexibleTopAppBar( GlassMediumFlexibleTopAppBar(
title = { Text(if (state.id > 0) "编辑替换规则" else "新增替换规则") }, title = if (state.id > 0) "编辑替换规则" else "新增替换规则",
navigationIcon = { navigationIcon = {
TopbarNavigationButton(onClick = onBack) TopbarNavigationButton(onClick = onBack)
}, },
@@ -143,14 +143,14 @@ fun ReplaceEditScreen(
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuItem(
text = { Text("复制规则") }, text = { AppText("复制规则") },
onClick = { onClick = {
showMenu = false showMenu = false
viewModel.copyRule() viewModel.copyRule()
} }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text("粘贴规则") }, text = { AppText("粘贴规则") },
onClick = { onClick = {
showMenu = false showMenu = false
viewModel.pasteRule(onSuccess = {}) viewModel.pasteRule(onSuccess = {})
@@ -167,7 +167,7 @@ fun ReplaceEditScreen(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider( positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above TooltipAnchorPosition.Above
), ),
tooltip = { PlainTooltip { Text("添加") } }, tooltip = { PlainTooltip { AppText("添加") } },
state = rememberTooltipState(), state = rememberTooltipState(),
) { ) {
FloatingActionButton( FloatingActionButton(
@@ -214,7 +214,7 @@ fun ReplaceEditScreen(
OutlinedTextField( OutlinedTextField(
value = state.name, value = state.name,
onValueChange = viewModel::onNameChange, onValueChange = viewModel::onNameChange,
label = { Text("规则名称") }, label = { AppText("规则名称") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { .onFocusChanged {
@@ -234,8 +234,8 @@ fun ReplaceEditScreen(
OutlinedTextField( OutlinedTextField(
value = state.pattern, value = state.pattern,
onValueChange = viewModel::onPatternChange, onValueChange = viewModel::onPatternChange,
label = { Text("匹配规则") }, label = { AppText("匹配规则") },
placeholder = { Text("输入正则表达式或关键字") }, placeholder = { AppText("输入正则表达式或关键字") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { .onFocusChanged {
@@ -247,8 +247,8 @@ fun ReplaceEditScreen(
OutlinedTextField( OutlinedTextField(
value = state.replacement, value = state.replacement,
onValueChange = viewModel::onReplacementChange, onValueChange = viewModel::onReplacementChange,
label = { Text("替换为") }, label = { AppText("替换为") },
placeholder = { Text("输入替换内容或捕获组") }, placeholder = { AppText("输入替换内容或捕获组") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { .onFocusChanged {
@@ -265,7 +265,7 @@ fun ReplaceEditScreen(
FilterChip( FilterChip(
selected = state.scopeTitle, selected = state.scopeTitle,
onClick = { viewModel.onScopeTitleChange(!state.scopeTitle) }, onClick = { viewModel.onScopeTitleChange(!state.scopeTitle) },
label = { Text("标题") }, label = { AppText("标题") },
leadingIcon = if (state.scopeTitle) { leadingIcon = if (state.scopeTitle) {
{ {
Icon( Icon(
@@ -282,7 +282,7 @@ fun ReplaceEditScreen(
FilterChip( FilterChip(
selected = state.scopeContent, selected = state.scopeContent,
onClick = { viewModel.onScopeContentChange(!state.scopeContent) }, onClick = { viewModel.onScopeContentChange(!state.scopeContent) },
label = { Text("内容") }, label = { AppText("内容") },
leadingIcon = if (state.scopeContent) { leadingIcon = if (state.scopeContent) {
{ {
Icon( Icon(
@@ -299,7 +299,7 @@ fun ReplaceEditScreen(
FilterChip( FilterChip(
selected = state.isRegex, selected = state.isRegex,
onClick = { viewModel.onRegexChange(!state.isRegex) }, onClick = { viewModel.onRegexChange(!state.isRegex) },
label = { Text("使用正则") }, label = { AppText("使用正则") },
leadingIcon = if (state.isRegex) { leadingIcon = if (state.isRegex) {
{ {
Icon( Icon(
@@ -316,8 +316,8 @@ fun ReplaceEditScreen(
OutlinedTextField( OutlinedTextField(
value = state.scope, value = state.scope,
onValueChange = viewModel::onScopeChange, onValueChange = viewModel::onScopeChange,
label = { Text("特定范围") }, label = { AppText("特定范围") },
placeholder = { Text("指定规则适用的范围") }, placeholder = { AppText("指定规则适用的范围") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { .onFocusChanged {
@@ -329,8 +329,8 @@ fun ReplaceEditScreen(
OutlinedTextField( OutlinedTextField(
value = state.excludeScope, value = state.excludeScope,
onValueChange = viewModel::onExcludeScopeChange, onValueChange = viewModel::onExcludeScopeChange,
label = { Text("排除范围") }, label = { AppText("排除范围") },
placeholder = { Text("指定规则不适用的范围") }, placeholder = { AppText("指定规则不适用的范围") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onFocusChanged { .onFocusChanged {
@@ -342,8 +342,8 @@ fun ReplaceEditScreen(
OutlinedTextField( OutlinedTextField(
value = state.timeout, value = state.timeout,
onValueChange = viewModel::onTimeoutChange, onValueChange = viewModel::onTimeoutChange,
label = { Text("超时 (ms)") }, label = { AppText("超时 (ms)") },
placeholder = { Text("3000") }, placeholder = { AppText("3000") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
@@ -383,8 +383,8 @@ fun GroupSelector(
OutlinedTextField( OutlinedTextField(
value = currentGroup, value = currentGroup,
onValueChange = onGroupChange, onValueChange = onGroupChange,
label = { Text("分组") }, label = { AppText("分组") },
placeholder = { Text("默认") }, placeholder = { AppText("默认") },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(), colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
modifier = Modifier modifier = Modifier
@@ -400,7 +400,7 @@ fun GroupSelector(
) { ) {
allGroups.forEach { selectionOption -> allGroups.forEach { selectionOption ->
DropdownMenuItem( DropdownMenuItem(
text = { Text(selectionOption) }, text = { AppText(selectionOption) },
onClick = { onClick = {
onGroupChange(selectionOption) onGroupChange(selectionOption)
expanded = false expanded = false
@@ -426,9 +426,9 @@ fun ManageGroupDialog(
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text("分组管理") }, title = { AppText("分组管理") },
text = { text = {
if (groups.isEmpty()) Text("暂无其他分组") if (groups.isEmpty()) AppText("暂无其他分组")
else Column( else Column(
modifier = Modifier.verticalScroll(rememberScrollState()), modifier = Modifier.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
@@ -448,7 +448,7 @@ fun ManageGroupDialog(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Checkbox(checked = isSelected, onCheckedChange = null) 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 = "删除选中" text = "删除选中"
) )
}, },
dismissButton = { TextButton(onClick = onDismiss) { Text("关闭") } } dismissButton = { TextButton(onClick = onDismiss) { AppText("关闭") } }
) )
} }
@@ -482,7 +482,7 @@ fun QuickInputBar(
symbols.forEach { symbol -> symbols.forEach { symbol ->
AssistChip( AssistChip(
onClick = { onInsert(symbol) }, onClick = { onInsert(symbol) },
label = { Text(symbol) }, label = { AppText(symbol) },
modifier = Modifier.padding(end = 8.dp) modifier = Modifier.padding(end = 8.dp)
) )
} }
@@ -19,7 +19,6 @@ import androidx.compose.material.icons.filled.Group
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue 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.divider.PillDivider
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem 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.rules.RuleListScaffold
import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -133,7 +133,7 @@ fun RssFavoritesScreen(
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Group, null, modifier = Modifier.size(18.dp)) Icon(Icons.Default.Group, null, modifier = Modifier.size(18.dp))
Spacer(Modifier.width(12.dp)) Spacer(Modifier.width(12.dp))
Text(stringResource(R.string.all)) AppText(stringResource(R.string.all))
} }
}, },
onClick = { onClick = {
@@ -151,7 +151,7 @@ fun RssFavoritesScreen(
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
Spacer(Modifier.width(12.dp)) Spacer(Modifier.width(12.dp))
Text(group) AppText(group)
} }
}, },
onClick = { onClick = {
@@ -166,7 +166,7 @@ fun RssFavoritesScreen(
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.DeleteSweep, null, modifier = Modifier.size(18.dp)) Icon(Icons.Default.DeleteSweep, null, modifier = Modifier.size(18.dp))
Spacer(Modifier.width(12.dp)) Spacer(Modifier.width(12.dp))
Text(stringResource(R.string.delete_select_group)) AppText(stringResource(R.string.delete_select_group))
} }
}, },
onClick = { onClick = {
@@ -179,7 +179,7 @@ fun RssFavoritesScreen(
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.DeleteForever, null, modifier = Modifier.size(18.dp)) Icon(Icons.Default.DeleteForever, null, modifier = Modifier.size(18.dp))
Spacer(Modifier.width(12.dp)) Spacer(Modifier.width(12.dp))
Text(stringResource(R.string.all)) AppText(stringResource(R.string.all))
} }
}, },
onClick = { onClick = {
@@ -248,14 +248,14 @@ fun RssFavoritesScreen(
}, },
dropdownContent = { dismiss -> dropdownContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.change_group)) }, text = { AppText(stringResource(R.string.change_group)) },
onClick = { onClick = {
showSetGroupDialog = rssStar showSetGroupDialog = rssStar
dismiss() dismiss()
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.delete)) }, text = { AppText(stringResource(R.string.delete)) },
onClick = { onClick = {
viewModel.deleteStar(rssStar) viewModel.deleteStar(rssStar)
dismiss() dismiss()
@@ -17,11 +17,9 @@ import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -43,6 +41,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseRuleEvent import io.legado.app.base.BaseRuleEvent
import io.legado.app.data.entities.RssSource 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.ActionItem
import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.DraggableSelectionHandler
import io.legado.app.ui.widget.components.GroupManageBottomSheet 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.RoundDropdownMenu
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem 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.rules.RuleListScaffold
import io.legado.app.ui.widget.components.text.AppText
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
import sh.calvin.reorderable.rememberReorderableLazyListState import sh.calvin.reorderable.rememberReorderableLazyListState
@@ -209,8 +209,12 @@ fun RssSourceScreen(
onConfirm = { viewModel.saveImportedRules() }, onConfirm = { viewModel.saveImportedRules() },
itemContent = { source, _ -> itemContent = { source, _ ->
Column { Column {
Text(source.sourceName, style = MaterialTheme.typography.titleMedium) AppText(source.sourceName, style = LegadoTheme.typography.titleMedium)
Text(source.sourceUrl, style = MaterialTheme.typography.bodySmall, maxLines = 1) AppText(
source.sourceUrl,
style = LegadoTheme.typography.bodySmall,
maxLines = 1
)
} }
} }
) )
@@ -225,16 +229,16 @@ fun RssSourceScreen(
showDeleteRuleDialog?.let { source -> showDeleteRuleDialog?.let { source ->
AlertDialog( AlertDialog(
onDismissRequest = { showDeleteRuleDialog = null }, onDismissRequest = { showDeleteRuleDialog = null },
title = { Text(stringResource(R.string.delete)) }, title = { AppText(stringResource(R.string.delete)) },
text = { Text(stringResource(R.string.del_msg)) }, text = { AppText(stringResource(R.string.del_msg)) },
confirmButton = { confirmButton = {
OutlinedButton(onClick = { OutlinedButton(onClick = {
viewModel.del(source); showDeleteRuleDialog = null viewModel.del(source); showDeleteRuleDialog = null
}) { Text(stringResource(R.string.ok)) } }) { AppText(stringResource(R.string.ok)) }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { showDeleteRuleDialog = null }) { TextButton(onClick = { showDeleteRuleDialog = null }) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -287,11 +291,11 @@ fun RssSourceScreen(
dropDownMenuContent = { dismiss -> dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
onClick = { showGroupManageSheet = true }, onClick = { showGroupManageSheet = true },
text = { Text("分组管理") }, text = { AppText("分组管理") },
) )
Box { Box {
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_rss_source)) }, text = { AppText(stringResource(R.string.import_rss_source)) },
onClick = { showImportMenu = true } onClick = { showImportMenu = true }
) )
RoundDropdownMenu( RoundDropdownMenu(
@@ -299,7 +303,7 @@ fun RssSourceScreen(
onDismissRequest = { showImportMenu = false } onDismissRequest = { showImportMenu = false }
) { ) {
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_on_line)) }, text = { AppText(stringResource(R.string.import_on_line)) },
onClick = { onClick = {
showImportMenu = false showImportMenu = false
dismiss() dismiss()
@@ -307,7 +311,7 @@ fun RssSourceScreen(
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_local)) }, text = { AppText(stringResource(R.string.import_local)) },
onClick = { onClick = {
showImportMenu = false showImportMenu = false
dismiss() dismiss()
@@ -315,7 +319,7 @@ fun RssSourceScreen(
} }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.import_default_rule)) }, text = { AppText(stringResource(R.string.import_default_rule)) },
onClick = { onClick = {
showImportMenu = false showImportMenu = false
dismiss() dismiss()
@@ -326,29 +330,29 @@ fun RssSourceScreen(
} }
PillDivider() PillDivider()
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.all)) }, text = { AppText(stringResource(R.string.all)) },
onClick = { dismiss(); viewModel.setGroupFilter(null) } onClick = { dismiss(); viewModel.setGroupFilter(null) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.enabled)) }, text = { AppText(stringResource(R.string.enabled)) },
onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_ENABLED) } onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_ENABLED) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.disabled)) }, text = { AppText(stringResource(R.string.disabled)) },
onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_DISABLED) } onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_DISABLED) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.need_login)) }, text = { AppText(stringResource(R.string.need_login)) },
onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_LOGIN) } onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_LOGIN) }
) )
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.no_group)) }, text = { AppText(stringResource(R.string.no_group)) },
onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_NO_GROUP) } onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_NO_GROUP) }
) )
PillDivider() PillDivider()
groups.forEach { group -> groups.forEach { group ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(group) }, text = { AppText(group) },
onClick = { dismiss(); viewModel.setGroupFilter("${RssSourceViewModel.PREFIX_GROUP}$group") } onClick = { dismiss(); viewModel.setGroupFilter("${RssSourceViewModel.PREFIX_GROUP}$group") }
) )
} }
@@ -22,11 +22,9 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.PlainTooltip import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TooltipAnchorPosition import androidx.compose.material3.TooltipAnchorPosition
import androidx.compose.material3.TooltipBox 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.ImportBookSourceDialog
import io.legado.app.ui.association.ImportReplaceRuleDialog import io.legado.app.ui.association.ImportReplaceRuleDialog
import io.legado.app.ui.association.ImportRssSourceDialog 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.EmptyMessageView
import io.legado.app.ui.widget.components.card.SelectionItemCard 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.CheckboxGroupContainer
import io.legado.app.ui.widget.components.checkBox.CheckboxItem 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.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.rules.RuleListScaffold 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.showDialogFragment
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
@@ -93,7 +93,7 @@ fun RuleSubScreen(
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.AutoMirrored.Filled.Sort, null, modifier = Modifier.size(18.dp)) Icon(Icons.AutoMirrored.Filled.Sort, null, modifier = Modifier.size(18.dp))
Spacer(Modifier.size(12.dp)) Spacer(Modifier.size(12.dp))
Text(stringResource(R.string.sort)) AppText(stringResource(R.string.sort))
} }
}, },
onClick = { onClick = {
@@ -106,7 +106,7 @@ fun RuleSubScreen(
TooltipBox( TooltipBox(
positionProvider = positionProvider =
TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above), TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = { PlainTooltip { Text("Localized description") } }, tooltip = { PlainTooltip { AppText("Localized description") } },
state = rememberTooltipState(), state = rememberTooltipState(),
) { ) {
FloatingActionButton( FloatingActionButton(
@@ -185,7 +185,7 @@ fun RuleSubScreen(
}, },
dropdownContent = { dismiss -> dropdownContent = { dismiss ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(stringResource(R.string.delete)) }, text = { AppText(stringResource(R.string.delete)) },
onClick = { onClick = {
viewModel.delete(ruleSub) viewModel.delete(ruleSub)
dismiss() dismiss()
@@ -226,24 +226,24 @@ fun RuleSubEditDialog(
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text(stringResource(R.string.rule_subscription)) }, title = { AppText(stringResource(R.string.rule_subscription)) },
text = { text = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField( OutlinedTextField(
value = name, value = name,
onValueChange = { name = it }, onValueChange = { name = it },
label = { Text(stringResource(R.string.name)) }, label = { AppText(stringResource(R.string.name)) },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
OutlinedTextField( OutlinedTextField(
value = url, value = url,
onValueChange = { url = it }, onValueChange = { url = it },
label = { Text("URL") }, label = { AppText("URL") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Text( AppText(
text = "订阅类型", text = "订阅类型",
style = MaterialTheme.typography.titleSmall, style = LegadoTheme.typography.titleSmall,
modifier = Modifier.padding(top = 8.dp) modifier = Modifier.padding(top = 8.dp)
) )
CheckboxGroupContainer(columns = 2) { CheckboxGroupContainer(columns = 2) {
@@ -265,12 +265,12 @@ fun RuleSubEditDialog(
TextButton(onClick = { TextButton(onClick = {
onConfirm(ruleSub.copy(name = name, url = url, type = type)) onConfirm(ruleSub.copy(name = name, url = url, type = type))
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismiss) { TextButton(onClick = onDismiss) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -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)
}
@@ -7,9 +7,13 @@ import androidx.compose.material3.MotionScheme
import androidx.compose.material3.Shapes import androidx.compose.material3.Shapes
import androidx.compose.material3.Typography import androidx.compose.material3.Typography
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import io.legado.app.ui.config.themeConfig.ThemeConfig 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) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -20,29 +24,82 @@ fun AppTheme(
val context = LocalContext.current val context = LocalContext.current
val appThemeMode = ThemeResolver.resolveThemeMode(ThemeConfig.appTheme) val appThemeMode = ThemeResolver.resolveThemeMode(ThemeConfig.appTheme)
val isPureBlack = ThemeConfig.isPureBlack val isPureBlack = ThemeConfig.isPureBlack
val paletteStyle = ThemeConfig.paletteStyle val paletteStyleStr = ThemeConfig.paletteStyle
val materialVersion = ThemeConfig.materialVersion 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 = val colorScheme =
remember(context, appThemeMode, darkTheme, isPureBlack, paletteStyle, materialVersion) { remember(context, appThemeMode, darkTheme, isPureBlack, paletteStyleStr, materialVersion) {
ThemeManager.getColorScheme( ThemeManager.getColorScheme(
context = context, context = context,
mode = appThemeMode, mode = appThemeMode,
darkTheme = darkTheme, darkTheme = darkTheme,
isAmoled = isPureBlack, isAmoled = isPureBlack,
paletteStyle = paletteStyle, paletteStyle = paletteStyleStr,
materialVersion = materialVersion materialVersion = materialVersion
) )
} }
MaterialExpressiveTheme( val themeColors = remember(colorScheme, darkTheme, seedColor, paletteStyle, colorSchemeMode) {
colorScheme = colorScheme, LegadoThemeColors(
typography = Typography(), colorScheme = colorScheme,
motionScheme = MotionScheme.expressive(), isDark = darkTheme,
shapes = Shapes() seedColor = seedColor,
paletteStyle = paletteStyle,
themeMode = colorSchemeMode,
useDynamicColor = appThemeMode == AppThemeMode.Dynamic,
composeEngine = composeEngine
)
}
CompositionLocalProvider(
LocalLegadoThemeColors provides themeColors
) { ) {
AppBackground(darkTheme = darkTheme) { when {
content() 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()
}
}
}
} }
} }
} }
@@ -7,8 +7,8 @@ import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.hazeEffect import dev.chrisbanes.haze.hazeEffect
import dev.chrisbanes.haze.hazeSource import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi 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.config.themeConfig.ThemeConfig
import io.legado.app.ui.theme.hazeStyle.HazeLegado
/** /**
* 自动感知全局配置的 HazeSource * 自动感知全局配置的 HazeSource
@@ -31,9 +31,9 @@ fun Modifier.responsiveHazeEffect(
if (!enableBlur) return this if (!enableBlur) return this
val style = if (enableProgressiveBlur) { val style = if (enableProgressiveBlur) {
HazeMaterials.ultraThin() HazeLegado.ultraThin()
} else { } else {
HazeMaterials.regular() HazeLegado.regular()
} }
return this.hazeEffect( return this.hazeEffect(
@@ -61,6 +61,6 @@ fun Modifier.regularHazeEffect(state: HazeState): Modifier {
return this.hazeEffect( return this.hazeEffect(
state = state, state = state,
style = HazeMaterials.ultraThin() style = HazeLegado.ultraThin()
) )
} }
@@ -0,0 +1,85 @@
package io.legado.app.ui.theme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.Typography
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
import com.materialkolor.PaletteStyle
import dev.chrisbanes.haze.HazeState
import top.yukonga.miuix.kmp.theme.ColorSchemeMode
data class LegadoThemeColors(
val colorScheme: ColorScheme,
val isDark: Boolean,
val seedColor: Color,
val paletteStyle: PaletteStyle,
val themeMode: ColorSchemeMode,
val useDynamicColor: Boolean,
val composeEngine: String,
)
val LocalLegadoThemeColors = staticCompositionLocalOf {
LegadoThemeColors(
colorScheme = lightColorScheme(),
isDark = false,
seedColor = Color.Unspecified,
paletteStyle = PaletteStyle.TonalSpot,
themeMode = ColorSchemeMode.System,
useDynamicColor = true,
composeEngine = "m3"
)
}
val LocalLegadoTypography = staticCompositionLocalOf {
Typography()
}
val LocalHazeState = compositionLocalOf<HazeState?> { null }
object LegadoTheme {
val colorScheme: ColorScheme
@Composable
@ReadOnlyComposable
get() = LocalLegadoThemeColors.current.colorScheme
val isDark: Boolean
@Composable
@ReadOnlyComposable
get() = LocalLegadoThemeColors.current.isDark
val seedColor: Color
@Composable
@ReadOnlyComposable
get() = LocalLegadoThemeColors.current.seedColor
val paletteStyle: PaletteStyle
@Composable
@ReadOnlyComposable
get() = LocalLegadoThemeColors.current.paletteStyle
val themeMode: ColorSchemeMode
@Composable
@ReadOnlyComposable
get() = LocalLegadoThemeColors.current.themeMode
val composeEngine: String
@Composable
@ReadOnlyComposable
get() = LocalLegadoThemeColors.current.composeEngine
val useDynamicColor: Boolean
@Composable
@ReadOnlyComposable
get() = LocalLegadoThemeColors.current.useDynamicColor
val typography: Typography
@Composable
@ReadOnlyComposable
get() = LocalLegadoTypography.current
}
@@ -4,6 +4,7 @@ import com.materialkolor.Contrast
import com.materialkolor.PaletteStyle import com.materialkolor.PaletteStyle
import com.materialkolor.dynamiccolor.ColorSpec import com.materialkolor.dynamiccolor.ColorSpec
import io.legado.app.ui.config.themeConfig.ThemeConfig import io.legado.app.ui.config.themeConfig.ThemeConfig
import top.yukonga.miuix.kmp.theme.ColorSchemeMode
object ThemeResolver { 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 { fun resolveColorSpecVersion(colorSpec: ThemeColorSpec): ColorSpec.SpecVersion {
return when (colorSpec) { return when (colorSpec) {
ThemeColorSpec.SPEC_2025 -> ColorSpec.SpecVersion.SPEC_2025 ThemeColorSpec.SPEC_2025 -> ColorSpec.SpecVersion.SPEC_2025
@@ -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)
)
}
@@ -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),
),
)
}
@@ -13,7 +13,6 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment 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.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
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
@OptIn(ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -54,9 +55,9 @@ fun CollapsibleHeader(
if (titleContent != null) { if (titleContent != null) {
titleContent() titleContent()
} else { } else {
Text( AppText(
text = title, text = title,
style = MaterialTheme.typography.bodySmallEmphasized.copy( style = LegadoTheme.typography.bodySmallEmphasized.copy(
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
), ),
@@ -64,9 +65,9 @@ fun CollapsibleHeader(
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
subtitle?.let { subtitle?.let {
Text( AppText(
text = it, text = it,
style = MaterialTheme.typography.labelSmallEmphasized.copy( style = LegadoTheme.typography.labelSmallEmphasized.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
), ),
maxLines = 1, maxLines = 1,
@@ -9,7 +9,6 @@ import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.TextDecoration
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.TextUnit
import io.legado.app.ui.widget.components.text.AppText
@Composable @Composable
fun AnimatedText( fun AnimatedText(
@@ -60,7 +60,7 @@ fun AnimatedText(
}, },
label = "" label = ""
) { ) {
Text( AppText(
style = style, style = style,
color = color, color = color,
softWrap = softWrap, softWrap = softWrap,
@@ -117,7 +117,7 @@ fun AnimatedTextLine(
label = "LineAnimation", label = "LineAnimation",
modifier = modifier modifier = modifier
) { targetText -> ) { targetText ->
Text( AppText(
text = targetText, text = targetText,
modifier = modifier, modifier = modifier,
style = style, style = style,
@@ -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
)
}
}
}
@@ -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
)
}
}
@@ -3,7 +3,6 @@ package io.legado.app.ui.widget.components
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -11,29 +10,27 @@ import androidx.compose.material3.FabPosition
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScaffoldDefaults import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.material3.TopAppBarColors
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.contentColorFor import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import dev.chrisbanes.haze.HazeState import dev.chrisbanes.haze.HazeState
import io.legado.app.ui.config.themeConfig.ThemeConfig 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 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) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun AppScaffold( fun AppScaffold(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
title: (@Composable () -> Unit)? = null, topBar: @Composable (HazeState) -> Unit = {},
subtitle: (@Composable () -> Unit)? = null,
scrollBehavior: TopAppBarScrollBehavior? = null,
navigationIcon: @Composable () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {},
colors: TopAppBarColors = GlassTopAppBarDefaults.glassColors(),
topBar: @Composable () -> Unit = {},
bottomBar: @Composable () -> Unit = {}, bottomBar: @Composable () -> Unit = {},
snackbarHost: @Composable () -> Unit = {}, snackbarHost: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {}, floatingActionButton: @Composable () -> Unit = {},
@@ -45,47 +42,73 @@ fun AppScaffold(
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val hasImageBg = ThemeConfig.hasImageBg(isDark) val hasImageBg = ThemeConfig.hasImageBg(isDark)
val hazeState = remember { HazeState() } val hazeState = remember { HazeState() }
val composeEngine = LegadoTheme.composeEngine
val containerColor = if (hasImageBg) { val containerColor = if (hasImageBg) {
Color.Transparent Color.Transparent
} else { } else {
MaterialTheme.colorScheme.background LegadoTheme.colorScheme.background
} }
val finalTopBar = @Composable { val miuixContainerColor = if (hasImageBg) {
Box(modifier = Modifier.responsiveHazeEffect(state = hazeState)) { Color.Transparent
if (title != null) { } else {
GlassMediumFlexibleTopAppBar( MiuixTheme.colorScheme.surface
title = title, }
subtitle = subtitle,
scrollBehavior = scrollBehavior, CompositionLocalProvider(LocalHazeState provides hazeState) {
navigationIcon = navigationIcon, when {
actions = actions, ThemeResolver.isMiuixEngine(composeEngine) -> {
colors = colors val miuixFabPosition = when (floatingActionButtonPosition) {
) FabPosition.End -> MiuixFabPosition.End
} else { FabPosition.Center -> MiuixFabPosition.Center
topBar() 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)
}
}
} }
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.ContainedLoadingIndicator import androidx.compose.material3.ContainedLoadingIndicator
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf 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.TextUnit
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import io.legado.app.ui.theme.LegadoTheme
@OptIn(ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -70,7 +70,7 @@ fun EmptyMessageView(
AnimatedTextLine( AnimatedTextLine(
text = message, text = message,
style = MaterialTheme.typography.labelLarge, style = LegadoTheme.typography.labelLarge,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
maxLines = 2, maxLines = 2,
softWrap = true, softWrap = true,
@@ -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))
}
}
@@ -18,7 +18,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -31,9 +30,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R 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.button.SmallTextButton
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet 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.settingItem.SettingItem
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -52,10 +53,10 @@ fun GroupManageBottomSheet(
.padding(bottom = 16.dp), .padding(bottom = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Text( AppText(
modifier = Modifier.padding(bottom = 16.dp), modifier = Modifier.padding(bottom = 16.dp),
text = stringResource(R.string.group_manage), text = stringResource(R.string.group_manage),
style = MaterialTheme.typography.titleMedium style = LegadoTheme.typography.titleMedium
) )
LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) { LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
items(groups, key = { it }) { group -> items(groups, key = { it }) { group ->
@@ -115,7 +116,7 @@ private fun GroupItem(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.heightIn(min = 48.dp), .heightIn(min = 48.dp),
label = { Text(stringResource(R.string.edit)) }, label = { AppText(stringResource(R.string.edit)) },
contentPadding = PaddingValues( contentPadding = PaddingValues(
top = 4.dp, top = 4.dp,
bottom = 4.dp, bottom = 4.dp,
@@ -10,6 +10,40 @@ import androidx.compose.material3.SwitchDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector 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 @Composable
fun IconSwitch( fun IconSwitch(
@@ -26,7 +26,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -43,6 +42,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.ui.widget.components.button.SmallIconButton 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.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -104,7 +104,7 @@ fun SearchBarSection(
.fillMaxWidth() .fillMaxWidth()
.heightIn(min = 48.dp) .heightIn(min = 48.dp)
.padding(horizontal = 4.dp), .padding(horizontal = 4.dp),
placeholder = { Text(placeholder) }, placeholder = { AppText(placeholder) },
leadingIcon = leadingIcon, leadingIcon = leadingIcon,
trailingIcon = { trailingIcon = {
Row( Row(
@@ -15,7 +15,6 @@ import androidx.compose.material3.HorizontalFloatingToolbar
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.PlainTooltip import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Text
import androidx.compose.material3.TooltipAnchorPosition import androidx.compose.material3.TooltipAnchorPosition
import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.TooltipDefaults
@@ -27,6 +26,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.ui.widget.components.text.AppText
data class SelectionActions( data class SelectionActions(
val primaryAction: ActionItem, val primaryAction: ActionItem,
@@ -84,7 +84,7 @@ fun SelectionBottomBar(
) { ) {
secondaryActions.forEach { action -> secondaryActions.forEach { action ->
DropdownMenuItem( DropdownMenuItem(
text = { Text(action.text) }, text = { AppText(action.text) },
leadingIcon = action.icon, leadingIcon = action.icon,
onClick = { onClick = {
action.onClick() action.onClick()
@@ -101,7 +101,7 @@ fun SelectionBottomBar(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider( positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above TooltipAnchorPosition.Above
), ),
tooltip = { PlainTooltip { Text(primaryAction.text) } }, tooltip = { PlainTooltip { AppText(primaryAction.text) } },
state = rememberTooltipState(), state = rememberTooltipState(),
) { ) {
FilledIconButton( FilledIconButton(
@@ -7,14 +7,14 @@ import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape 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.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.draw.clip
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.widget.components.title.AdaptiveTitle
import top.yukonga.miuix.kmp.basic.Card as MiuixCard
/** /**
* Settings Group Container by https://github.com/wxxsfxyzm/InstallerX-Revived * Settings Group Container by https://github.com/wxxsfxyzm/InstallerX-Revived
@@ -29,24 +29,33 @@ fun SplicedColumnGroup(
title: String = "", title: String = "",
content: @Composable ColumnScope.() -> Unit, 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()) { if (title.isNotEmpty()) {
Text( AdaptiveTitle(
text = title, text = title,
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(start = 16.dp, bottom = 8.dp) modifier = Modifier.padding(start = 16.dp, bottom = 8.dp)
) )
} }
Card( if (ThemeResolver.isMiuixEngine(composeEngine)) {
shape = RoundedCornerShape(16.dp), MiuixCard {
colors = CardDefaults.cardColors(containerColor = Color.Transparent), Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.animateContentSize() .animateContentSize()
) { .clip(RoundedCornerShape(16.dp))
) {
content()
}
}
} else {
Column( Column(
modifier = Modifier
.fillMaxWidth()
.animateContentSize()
.clip(RoundedCornerShape(16.dp)),
verticalArrangement = Arrangement.spacedBy(2.dp) verticalArrangement = Arrangement.spacedBy(2.dp)
) { ) {
content() content()
@@ -15,7 +15,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -26,7 +25,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.data.entities.Bookmark 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.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -50,16 +51,16 @@ fun BookmarkEditSheet(
.padding(16.dp) .padding(16.dp)
.navigationBarsPadding() .navigationBarsPadding()
) { ) {
Text( AppText(
text = bookmark.chapterName, text = bookmark.chapterName,
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
modifier = Modifier.padding(bottom = 16.dp) modifier = Modifier.padding(bottom = 16.dp)
) )
OutlinedTextField( OutlinedTextField(
value = bookText, value = bookText,
onValueChange = { bookText = it }, onValueChange = { bookText = it },
label = { Text("原文") }, label = { AppText("原文") },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
maxLines = 10 maxLines = 10
) )
@@ -69,7 +70,7 @@ fun BookmarkEditSheet(
OutlinedTextField( OutlinedTextField(
value = content, value = content,
onValueChange = { content = it }, onValueChange = { content = it },
label = { Text("摘要/笔记") }, label = { AppText("摘要/笔记") },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
maxLines = 5 maxLines = 5
) )
@@ -86,7 +87,7 @@ fun BookmarkEditSheet(
colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.error), colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.error),
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) { ) {
Text("删除") AppText("删除")
} }
Button( Button(
@@ -99,7 +100,7 @@ fun BookmarkEditSheet(
}, },
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) { ) {
Text("保存") AppText("保存")
} }
} }
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
@@ -109,8 +110,8 @@ fun BookmarkEditSheet(
if (showDeleteConfirmDialog) { if (showDeleteConfirmDialog) {
AlertDialog( AlertDialog(
onDismissRequest = { showDeleteConfirmDialog = false }, onDismissRequest = { showDeleteConfirmDialog = false },
title = { Text("确认删除") }, title = { AppText("确认删除") },
text = { Text("你确定要删除这条书签吗?") }, text = { AppText("你确定要删除这条书签吗?") },
confirmButton = { confirmButton = {
TextButton( TextButton(
onClick = { onClick = {
@@ -119,14 +120,14 @@ fun BookmarkEditSheet(
}, },
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error) colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error)
) { ) {
Text("删除") AppText("删除")
} }
}, },
dismissButton = { dismissButton = {
TextButton( TextButton(
onClick = { showDeleteConfirmDialog = false } onClick = { showDeleteConfirmDialog = false }
) { ) {
Text("取消") AppText("取消")
} }
} }
) )
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier 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.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.data.entities.Bookmark 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) @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -49,17 +50,17 @@ fun BookmarkItem(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp) .padding(horizontal = 16.dp, vertical = 12.dp)
) { ) {
Text( AppText(
text = bookmark.chapterName, text = bookmark.chapterName,
style = MaterialTheme.typography.titleSmallEmphasized, style = LegadoTheme.typography.titleSmallEmphasized,
color = if (isDur) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary color = if (isDur) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary
) )
if (bookmark.bookText.isNotEmpty()) { if (bookmark.bookText.isNotEmpty()) {
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text( AppText(
text = bookmark.bookText, text = bookmark.bookText,
style = MaterialTheme.typography.bodyMedium, style = LegadoTheme.typography.bodyMedium,
maxLines = 2, maxLines = 2,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -68,9 +69,9 @@ fun BookmarkItem(
if (bookmark.content.isNotEmpty()) { if (bookmark.content.isNotEmpty()) {
Spacer(modifier = Modifier.height(2.dp)) Spacer(modifier = Modifier.height(2.dp))
Text( AppText(
text = bookmark.content, text = bookmark.content,
style = MaterialTheme.typography.bodyMedium, style = LegadoTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
} }
@@ -3,10 +3,10 @@ package io.legado.app.ui.widget.components.button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import io.legado.app.ui.widget.components.text.AppText
@Composable @Composable
fun AlertButton( fun AlertButton(
@@ -24,6 +24,6 @@ fun AlertButton(
containerColor = Color.Transparent, containerColor = Color.Transparent,
) )
) { ) {
Text(text = text) AppText(text = text)
} }
} }
@@ -8,8 +8,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.ToggleButton import androidx.compose.material3.ToggleButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -21,6 +19,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
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
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@OptIn(ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@@ -73,9 +73,9 @@ fun AnimatedActionButton(
AnimatedVisibility( AnimatedVisibility(
visible = showText visible = showText
) { ) {
Text( AppText(
text = if (lastCheckedState) activeText else inactiveText, text = if (lastCheckedState) activeText else inactiveText,
style = MaterialTheme.typography.labelMedium, style = LegadoTheme.typography.labelMedium,
modifier = Modifier.padding(start = 8.dp), modifier = Modifier.padding(start = 8.dp),
maxLines = 1, maxLines = 1,
softWrap = false softWrap = false
@@ -8,11 +8,11 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith import androidx.compose.animation.togetherWith
import androidx.compose.material3.ContainedLoadingIndicator import androidx.compose.material3.ContainedLoadingIndicator
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -38,7 +38,7 @@ fun AnimatedTextButton(
if (loading) { if (loading) {
ContainedLoadingIndicator() ContainedLoadingIndicator()
} else { } else {
Text(text) AppText(text)
} }
} }
} }
@@ -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
)
}
}
@@ -15,11 +15,9 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.IconToggleButtonShapes import androidx.compose.material3.IconToggleButtonShapes
import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedIconButton import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.OutlinedIconToggleButton import androidx.compose.material3.OutlinedIconToggleButton
import androidx.compose.material3.OutlinedToggleButton import androidx.compose.material3.OutlinedToggleButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -31,7 +29,13 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
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.text.AppText
import kotlinx.coroutines.delay 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) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@@ -41,22 +45,33 @@ fun SmallIconButton(
icon: ImageVector, icon: ImageVector,
contentDescription: String? = null contentDescription: String? = null
) { ) {
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { if (ThemeResolver.isMiuixEngine(composeEngine)) {
IconButton( MiuixIconButton(
onClick = onClick, onClick = onClick
modifier = Modifier.size(
IconButtonDefaults.extraSmallContainerSize(
IconButtonDefaults.IconButtonWidthOption.Uniform
)
),
shape = IconButtonDefaults.extraSmallRoundShape,
) { ) {
Icon( MiuixIcon(
imageVector = icon, imageVector = icon,
contentDescription = contentDescription, contentDescription = contentDescription
modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize),
) )
} }
} 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( AnimatedVisibility(
visible = showText visible = showText
) { ) {
Text( AppText(
text = if (lastCheckedState) activeText else inactiveText, text = if (lastCheckedState) activeText else inactiveText,
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
modifier = Modifier.padding(start = 6.dp), modifier = Modifier.padding(start = 6.dp),
maxLines = 1, maxLines = 1,
softWrap = false softWrap = false
@@ -6,12 +6,13 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
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 @Composable
fun SmallTextButton( fun SmallTextButton(
@@ -32,9 +33,9 @@ fun SmallTextButton(
modifier = Modifier.size(16.dp) modifier = Modifier.size(16.dp)
) )
Spacer(Modifier.width(4.dp)) Spacer(Modifier.width(4.dp))
Text( AppText(
text = text, text = text,
style = MaterialTheme.typography.labelMedium style = LegadoTheme.typography.labelMedium
) )
} }
} }
@@ -22,7 +22,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedIconButton import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.Text
import androidx.compose.material3.ToggleButton import androidx.compose.material3.ToggleButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect 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.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.ui.config.themeConfig.ThemeConfig 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 import kotlinx.coroutines.delay
enum class TopBarButtonVariant { enum class TopBarButtonVariant {
@@ -109,13 +111,22 @@ fun TopbarNavigationButton(
contentDescription: String? = "返回", contentDescription: String? = "返回",
style: TopBarButtonVariant = TopBarButtonVariant.Filled style: TopBarButtonVariant = TopBarButtonVariant.Filled
) { ) {
TopBarButton( if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
onClick = onClick, MiuixButton(
imageVector = imageVector, onClick = onClick,
contentDescription = contentDescription, imageVector = imageVector,
modifier = modifier.padding(horizontal = 12.dp), contentDescription = contentDescription,
style = style modifier = modifier.padding(horizontal = 16.dp)
) )
} else {
TopBarButton(
onClick = onClick,
imageVector = imageVector,
contentDescription = contentDescription,
modifier = modifier.padding(horizontal = 12.dp),
style = style
)
}
} }
@Composable @Composable
@@ -126,21 +137,29 @@ fun TopBarActionButton(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val enableProgressive = ThemeConfig.enableProgressiveBlur val enableProgressive = ThemeConfig.enableProgressiveBlur
if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
if (enableProgressive) { MiuixButton(
TopBarButton(
onClick = onClick, onClick = onClick,
imageVector = imageVector, imageVector = imageVector,
contentDescription = contentDescription, contentDescription = contentDescription,
modifier = modifier.padding(end = 12.dp), modifier = modifier.padding(end = 8.dp),
style = TopBarButtonVariant.Filled
) )
} else { } else {
IconButton(onClick = onClick) { if (enableProgressive) {
Icon( TopBarButton(
onClick = onClick,
imageVector = imageVector, 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 showText = false
} }
} }
if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
ToggleButton( MiuixToggleButton(
modifier = modifier.height(36.dp), checked = checked,
contentPadding = PaddingValues(horizontal = 8.dp), onCheckedChange = onCheckedChange,
checked = checked, iconChecked = iconChecked,
onCheckedChange = { iconUnchecked = iconUnchecked
lastCheckedState = it )
onCheckedChange(it) } else {
showText = true ToggleButton(
} modifier = modifier.height(36.dp),
) { contentPadding = PaddingValues(horizontal = 8.dp),
Row( checked = checked,
verticalAlignment = Alignment.CenterVertically, onCheckedChange = {
horizontalArrangement = Arrangement.Center lastCheckedState = it
) { onCheckedChange(it)
showText = true
AnimatedContent(
targetState = checked,
label = "IconAnimation"
) { targetChecked ->
AnimatedIcon(
modifier = Modifier.size(20.dp),
imageVector = if (targetChecked) iconChecked else iconUnchecked,
contentDescription = null
)
} }
) {
AnimatedVisibility( Row(
visible = showText verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) { ) {
Text(
text = if (lastCheckedState) activeText else inactiveText, AnimatedContent(
style = MaterialTheme.typography.labelMedium, targetState = checked,
modifier = Modifier.padding(start = 8.dp), label = "IconAnimation"
maxLines = 1, ) { targetChecked ->
softWrap = false 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
)
}
} }
} }
} }
@@ -4,14 +4,79 @@ import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardColors
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CardElevation import androidx.compose.material3.CardElevation
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape 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.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) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@@ -19,43 +84,50 @@ fun GlassCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
shape: Shape = CardDefaults.shape, shape: Shape = CardDefaults.shape,
colors: CardColors? = null, cornerRadius: Dp = MiuixCardDefaults.CornerRadius,
containerColor: Color? = null,
contentColor: Color? = null,
elevation: CardElevation = CardDefaults.cardElevation(), elevation: CardElevation = CardDefaults.cardElevation(),
border: BorderStroke? = null, border: BorderStroke? = null,
content: @Composable ColumnScope.() -> Unit 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( @OptIn(ExperimentalMaterialApi::class)
containerColor = MaterialTheme.colorScheme.secondaryContainer, @Composable
contentColor = MaterialTheme.colorScheme.onSecondaryContainer 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
)
}
} }
@@ -24,8 +24,6 @@ import androidx.compose.material3.Checkbox
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf 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.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex 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.button.SmallIconButton
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu 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.ReorderableItem
import sh.calvin.reorderable.ReorderableLazyListState import sh.calvin.reorderable.ReorderableLazyListState
import top.yukonga.miuix.kmp.basic.BasicComponent
import top.yukonga.miuix.kmp.theme.MiuixTheme
@Composable @Composable
fun SelectionItemCard( fun SelectionItemCard(
@@ -66,11 +71,14 @@ fun SelectionItemCard(
) { ) {
var showMenu by remember { mutableStateOf(false) } var showMenu by remember { mutableStateOf(false) }
val composeEngine = ThemeResolver.isMiuixEngine(composeEngine)
val animatedContainerColor by animateColorAsState( val animatedContainerColor by animateColorAsState(
targetValue = if (isSelected) targetValue = if (isSelected)
selectedContainerColor ?: MaterialTheme.colorScheme.secondaryContainer selectedContainerColor
?: if (composeEngine) MiuixTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.secondaryContainer
else else
containerColor ?: MaterialTheme.colorScheme.surfaceContainerLow, containerColor
?: if (composeEngine) MiuixTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.surfaceContainerLow,
animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing), animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing),
label = "CardColor" label = "CardColor"
) )
@@ -81,7 +89,7 @@ fun SelectionItemCard(
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.fillMaxWidth(), .fillMaxWidth(),
shape = MaterialTheme.shapes.medium, shape = MaterialTheme.shapes.medium,
colors = CardDefaults.cardColors(containerColor = animatedContainerColor), containerColor = animatedContainerColor,
elevation = CardDefaults.cardElevation(defaultElevation = elevation) elevation = CardDefaults.cardElevation(defaultElevation = elevation)
) { ) {
Row( Row(
@@ -113,28 +121,49 @@ fun SelectionItemCard(
} }
} }
ListItem( if (composeEngine) {
modifier = Modifier.weight(1f), BasicComponent(
headlineContent = { modifier = Modifier.weight(1f)
Text( ) {
AppText(
text = title, text = title,
style = MaterialTheme.typography.titleSmall, style = LegadoTheme.typography.titleSmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
}, if (!subtitle.isNullOrBlank()) {
supportingContent = if (!subtitle.isNullOrBlank()) { AppText(
{
Text(
text = subtitle, text = subtitle,
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis 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( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@@ -143,7 +172,7 @@ fun SelectionItemCard(
.padding(end = 8.dp) .padding(end = 8.dp)
) { ) {
onEnabledChange?.let { onEnabledChange?.let {
Switch( AdaptiveSwitch(
modifier = Modifier.scale(0.8f), modifier = Modifier.scale(0.8f),
checked = isEnabled, checked = isEnabled,
onCheckedChange = it onCheckedChange = it
@@ -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
)
}
}
}
@@ -6,50 +6,42 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape 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.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.TextStyle 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 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 import io.legado.app.ui.widget.components.AnimatedTextLine
@Preview(showBackground = true)
@Composable
fun PreviewTextCard() {
MaterialTheme {
TextCard(
text = "v1.0.0"
)
}
}
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
fun TextCard( fun TextCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
text: String, text: String,
icon: ImageVector? = null, icon: ImageVector? = null,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
backgroundColor: Color = colorScheme.primaryContainer, backgroundColor: Color = MaterialTheme.colorScheme.primaryContainer,
contentColor: Color = colorScheme.onPrimaryContainer, contentColor: Color = MaterialTheme.colorScheme.onPrimaryContainer,
cornerRadius: Dp = 8.dp, cornerRadius: Dp = 8.dp,
horizontalPadding: Dp = 8.dp, horizontalPadding: Dp = 8.dp,
verticalPadding: Dp = 2.dp, verticalPadding: Dp = 2.dp,
iconSize: Dp = 14.dp, iconSize: Dp = 14.dp,
spacing: Dp = 4.dp, spacing: Dp = 4.dp,
textStyle: TextStyle = MaterialTheme.typography.labelSmall textStyle: TextStyle = LegadoTheme.typography.labelSmallEmphasized
) { ) {
GlassCard( NormalCard(
modifier = modifier, modifier = modifier,
shape = RoundedCornerShape(cornerRadius), shape = RoundedCornerShape(cornerRadius),
colors = CardDefaults.cardColors(containerColor = backgroundColor), containerColor = backgroundColor,
contentColor = contentColor,
onClick = onClick onClick = onClick
) { ) {
Row( Row(
@@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Checkbox import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme 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.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.draw.clip
import androidx.compose.ui.graphics.Color 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
@Composable @Composable
fun CheckboxItem( fun CheckboxItem(
@@ -45,9 +46,9 @@ fun CheckboxItem(
enabled = enabled, enabled = enabled,
modifier = Modifier.alpha(alpha) modifier = Modifier.alpha(alpha)
) )
Text( AppText(
text = title, text = title,
style = MaterialTheme.typography.bodyMedium, style = LegadoTheme.typography.bodyMedium,
maxLines = 1, maxLines = 1,
modifier = Modifier modifier = Modifier
.padding(start = 12.dp) .padding(start = 12.dp)
@@ -13,7 +13,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.StrokeCap
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.card.TextCard import io.legado.app.ui.widget.components.card.TextCard
import top.yukonga.miuix.kmp.theme.MiuixTheme
@Composable @Composable
fun BookshelfCover( fun BookshelfCover(
@@ -27,6 +31,16 @@ fun BookshelfCover(
sourceOrigin: String? = null, sourceOrigin: String? = null,
onLoadFinish: (() -> Unit)? = 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) { Box(modifier = modifier) {
BookCover( BookCover(
name = name, name = name,
@@ -44,8 +58,8 @@ fun BookshelfCover(
modifier = Modifier modifier = Modifier
.align(Alignment.TopEnd) .align(Alignment.TopEnd)
.padding(2.dp), .padding(2.dp),
backgroundColor = MaterialTheme.colorScheme.secondaryContainer, backgroundColor = backgroundColor,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer, contentColor = contentColor,
cornerRadius = 4.dp, cornerRadius = 4.dp,
horizontalPadding = 4.dp, horizontalPadding = 4.dp,
verticalPadding = 0.dp verticalPadding = 0.dp
@@ -59,8 +73,8 @@ fun BookshelfCover(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 4.dp, vertical = 6.dp) .padding(horizontal = 4.dp, vertical = 6.dp)
.height(3.dp), .height(3.dp),
color = MaterialTheme.colorScheme.primary, color = LegadoTheme.colorScheme.primary,
trackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f), trackColor = LegadoTheme.colorScheme.primary.copy(alpha = 0.2f),
strokeCap = StrokeCap.Round strokeCap = StrokeCap.Round
) )
} }
@@ -22,7 +22,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue 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.HsvColorPicker
import com.github.skydoves.colorpicker.compose.rememberColorPickerController import com.github.skydoves.colorpicker.compose.rememberColorPickerController
import io.legado.app.R 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.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -86,9 +87,9 @@ fun ColorPickerSheet(
.padding(16.dp), .padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text( AppText(
text = "颜色选择", text = "颜色选择",
style = MaterialTheme.typography.titleLarge, style = LegadoTheme.typography.titleLarge,
modifier = Modifier.padding(bottom = 16.dp) modifier = Modifier.padding(bottom = 16.dp)
) )
@@ -168,9 +169,9 @@ fun ColorPickerSheet(
) )
) )
Spacer(modifier = Modifier.width(12.dp)) Spacer(modifier = Modifier.width(12.dp))
Text( AppText(
text = "#${Integer.toHexString(currentColor.toArgb()).uppercase()}", text = "#${Integer.toHexString(currentColor.toArgb()).uppercase()}",
style = MaterialTheme.typography.bodyLarge style = LegadoTheme.typography.bodyLarge
) )
Row( Row(
@@ -178,14 +179,14 @@ fun ColorPickerSheet(
horizontalArrangement = Arrangement.End horizontalArrangement = Arrangement.End
) { ) {
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Button(onClick = { Button(onClick = {
onColorSelected(currentColor.toArgb()) onColorSelected(currentColor.toArgb())
onDismissRequest() onDismissRequest()
}) { }) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
} }
} }
@@ -10,9 +10,7 @@ import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.AssistChip import androidx.compose.material3.AssistChip
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -22,6 +20,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
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 @Composable
fun TextListInputDialog( fun TextListInputDialog(
@@ -36,22 +36,22 @@ fun TextListInputDialog(
AlertDialog( AlertDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
title = { Text(title) }, title = { AppText(title) },
text = { text = {
Column { Column {
OutlinedTextField( OutlinedTextField(
value = text, value = text,
onValueChange = { text = it }, onValueChange = { text = it },
label = { Text(hint) }, label = { AppText(hint) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
singleLine = true singleLine = true
) )
if (suggestions.isNotEmpty()) { if (suggestions.isNotEmpty()) {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( AppText(
text = "建议:", text = "建议:",
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
modifier = Modifier.padding(bottom = 4.dp) modifier = Modifier.padding(bottom = 4.dp)
) )
LazyRow( LazyRow(
@@ -61,7 +61,7 @@ fun TextListInputDialog(
items(suggestions) { suggestion -> items(suggestions) { suggestion ->
AssistChip( AssistChip(
onClick = { text = suggestion }, onClick = { text = suggestion },
label = { Text(suggestion) } label = { AppText(suggestion) }
) )
} }
} }
@@ -72,12 +72,12 @@ fun TextListInputDialog(
TextButton( TextButton(
onClick = { onConfirm(text) } onClick = { onConfirm(text) }
) { ) {
Text(stringResource(android.R.string.ok)) AppText(stringResource(android.R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(stringResource(android.R.string.cancel)) AppText(stringResource(android.R.string.cancel))
} }
} }
) )
@@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.graphics.Color
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
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 @Composable
fun PillHeaderDivider( fun PillHeaderDivider(
@@ -40,9 +41,9 @@ fun PillHeaderDivider(
.background(dotColor) .background(dotColor)
) )
Text( AppText(
text = title, text = title,
style = MaterialTheme.typography.labelSmall, style = LegadoTheme.typography.labelSmall,
color = titleColor, color = titleColor,
modifier = Modifier.padding(horizontal = 12.dp), modifier = Modifier.padding(horizontal = 12.dp),
maxLines = 1 maxLines = 1
@@ -20,7 +20,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R 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.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
enum class FilePickerSheetMode { enum class FilePickerSheetMode {
DIR, FILE, EXPORT DIR, FILE, EXPORT
@@ -56,9 +57,9 @@ fun FilePickerSheet(
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text( AppText(
text = title, text = title,
style = MaterialTheme.typography.titleMedium, style = LegadoTheme.typography.titleMedium,
modifier = Modifier.padding(bottom = 20.dp) modifier = Modifier.padding(bottom = 20.dp)
) )
@@ -141,9 +142,9 @@ private fun RowScope.FilePickerOptionCard(
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( AppText(
text = text, text = text,
style = MaterialTheme.typography.labelMedium, style = LegadoTheme.typography.labelMedium,
maxLines = 1 maxLines = 1
) )
} }
@@ -25,7 +25,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedIconButton import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp 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.button.AnimatedActionButton
import io.legado.app.ui.widget.components.text.AppText
import java.time.LocalDate import java.time.LocalDate
/** /**
@@ -60,7 +61,7 @@ fun HeatmapCalendarTopBar(
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text("时间线", style = MaterialTheme.typography.titleMedium) AppText("时间线", style = LegadoTheme.typography.titleMedium)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
AnimatedActionButton( AnimatedActionButton(
@@ -107,7 +108,7 @@ fun WeekdayLabelsColumn(
labels.forEachIndexed { index, label -> labels.forEachIndexed { index, label ->
if (index % 2 == 0) { if (index % 2 == 0) {
Text( AppText(
text = label, text = label,
fontSize = 10.sp, fontSize = 10.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
@@ -170,7 +171,7 @@ fun NoEarlierDataIndicator(
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
"没有更早数据".forEach { char -> "没有更早数据".forEach { char ->
Text( AppText(
text = char.toString(), text = char.toString(),
fontSize = 9.sp, fontSize = 9.sp,
lineHeight = 12.sp, lineHeight = 12.sp,
@@ -252,7 +253,7 @@ fun HeatmapWeekColumn(
// 月份标签 // 月份标签
if (firstDayOfMonth != null) { if (firstDayOfMonth != null) {
Text( AppText(
text = "${firstDayOfMonth.monthValue}", text = "${firstDayOfMonth.monthValue}",
fontSize = 10.sp, fontSize = 10.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
@@ -280,9 +281,9 @@ fun HeatmapLegend(
) { ) {
val legendUnit = if (mode == HeatmapMode.COUNT) "" else "" val legendUnit = if (mode == HeatmapMode.COUNT) "" else ""
Text( AppText(
"少($legendUnit)", "少($legendUnit)",
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = Color.Gray color = Color.Gray
) )
@@ -298,9 +299,9 @@ fun HeatmapLegend(
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
} }
Text( AppText(
"多($legendUnit)", "多($legendUnit)",
style = MaterialTheme.typography.bodySmall, style = LegadoTheme.typography.bodySmall,
color = Color.Gray color = Color.Gray
) )
} }
@@ -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
)
}
}
@@ -42,7 +42,6 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedToggleButton import androidx.compose.material3.OutlinedToggleButton
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberModalBottomSheetState 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.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R 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.AnimatedText
import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.AppScaffold
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable
@@ -77,25 +78,25 @@ fun SourceInputDialog(
AlertDialog( AlertDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
title = { Text(title) }, title = { AppText(title) },
text = { text = {
Column { Column {
OutlinedTextField( OutlinedTextField(
value = text, value = text,
onValueChange = { text = it }, onValueChange = { text = it },
label = { Text(hint) }, label = { AppText(hint) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
maxLines = 5 maxLines = 5
) )
if (historyValues.isNotEmpty()) { if (historyValues.isNotEmpty()) {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text("历史记录:", style = MaterialTheme.typography.labelSmall) AppText("历史记录:", style = LegadoTheme.typography.labelSmall)
LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp)) { LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
items(historyValues) { history -> items(historyValues) { history ->
AssistChip( AssistChip(
onClick = { text = history }, onClick = { text = history },
label = { Text(history, maxLines = 1) } label = { AppText(history, maxLines = 1) }
) )
} }
} }
@@ -105,11 +106,11 @@ fun SourceInputDialog(
confirmButton = { confirmButton = {
OutlinedButton( OutlinedButton(
onClick = { if (text.isNotBlank()) onConfirm(text) } onClick = { if (text.isNotBlank()) onConfirm(text) }
) { Text(stringResource(android.R.string.ok)) } ) { AppText(stringResource(android.R.string.ok)) }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(stringResource(android.R.string.cancel)) AppText(stringResource(android.R.string.cancel))
} }
} }
) )
@@ -254,14 +255,14 @@ private fun ImportItemRow(
) )
}, },
supportingContent = { supportingContent = {
Text( AppText(
text = when (status) { text = when (status) {
ImportStatus.New -> "新增" ImportStatus.New -> "新增"
ImportStatus.Update -> "更新" ImportStatus.Update -> "更新"
ImportStatus.Existing -> "已有" ImportStatus.Existing -> "已有"
ImportStatus.Error -> "错误" ImportStatus.Error -> "错误"
}, },
style = MaterialTheme.typography.labelMedium, style = LegadoTheme.typography.labelMedium,
color = when (status) { color = when (status) {
ImportStatus.New -> MaterialTheme.colorScheme.primary ImportStatus.New -> MaterialTheme.colorScheme.primary
ImportStatus.Update -> MaterialTheme.colorScheme.secondary ImportStatus.Update -> MaterialTheme.colorScheme.secondary
@@ -315,12 +316,12 @@ fun ImportBottomBar(
) )
} }
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedButton(onClick = onCancel) { Text("取消") } OutlinedButton(onClick = onCancel) { AppText("取消") }
Button( Button(
enabled = selectedCount > 0, enabled = selectedCount > 0,
onClick = onConfirm onClick = onConfirm
) { ) {
Text("导入") AppText("导入")
} }
} }
} }
@@ -15,19 +15,11 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState 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.animateFloatingActionButton
import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment 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.input.nestedscroll.nestedScroll
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex 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.AppScaffold
import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
import io.legado.app.ui.widget.components.SelectionActions import io.legado.app.ui.widget.components.SelectionActions
import io.legado.app.ui.widget.components.SelectionBottomBar 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.DynamicTopAppBar
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarScrollBehavior
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -52,28 +46,21 @@ fun <T> ListScaffold(
onSearchQueryChange: (String) -> Unit, onSearchQueryChange: (String) -> Unit,
searchPlaceholder: String = "搜索...", searchPlaceholder: String = "搜索...",
topBarActions: @Composable RowScope.() -> Unit = {}, topBarActions: @Composable RowScope.() -> Unit = {},
bottomContent: @Composable (ColumnScope.(TopAppBarScrollBehavior) -> Unit)? = null, bottomContent: @Composable (ColumnScope.(GlassTopAppBarScrollBehavior) -> Unit)? = null,
dropDownMenuContent: @Composable (ColumnScope.(dismiss: () -> Unit) -> Unit)? = null, dropDownMenuContent: @Composable (ColumnScope.(dismiss: () -> Unit) -> Unit)? = null,
selectionActions: SelectionActions? = null, selectionActions: SelectionActions? = null,
onAddClick: (() -> Unit)? = null, onAddClick: (() -> Unit)? = null,
floatingActionButton: @Composable () -> Unit = { floatingActionButton: @Composable () -> Unit = {
onAddClick?.let { onClick -> onAddClick?.let { onClick ->
TooltipBox( AppFloatingActionButton(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider( onClick = onClick,
TooltipAnchorPosition.Above modifier = Modifier.animateFloatingActionButton(
visible = state.selectedIds.isEmpty(),
alignment = Alignment.BottomEnd,
), ),
tooltip = { PlainTooltip { Text("添加") } }, tooltipText = "添加"
state = rememberTooltipState(),
) { ) {
FloatingActionButton( Icon(Icons.Default.Add, contentDescription = "Add")
modifier = Modifier.animateFloatingActionButton(
visible = state.selectedIds.isEmpty(),
alignment = Alignment.BottomEnd,
),
onClick = onClick
) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
} }
} }
}, },
@@ -25,6 +25,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
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.rememberOpaqueColorScheme import io.legado.app.ui.theme.rememberOpaqueColorScheme
@Composable @Composable
@@ -57,7 +58,7 @@ fun RoundDropdownMenuItem(
) { ) {
CompositionLocalProvider( CompositionLocalProvider(
LocalContentColor provides contentColor, LocalContentColor provides contentColor,
LocalTextStyle provides MaterialTheme.typography.labelLarge LocalTextStyle provides LegadoTheme.typography.labelLarge
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@@ -22,7 +22,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -37,6 +36,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R import io.legado.app.R
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** /**
@@ -84,7 +84,7 @@ fun <T> RuleEditSheet(
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
CenterAlignedTopAppBar( CenterAlignedTopAppBar(
title = { Text(title) }, title = { AppText(title) },
navigationIcon = { navigationIcon = {
IconButton(onClick = onDismissRequest) { IconButton(onClick = onDismissRequest) {
Icon( Icon(
@@ -99,7 +99,7 @@ fun <T> RuleEditSheet(
} }
DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) { DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.copy_rule)) }, text = { AppText(stringResource(R.string.copy_rule)) },
leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) }, leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) },
onClick = { onClick = {
onCopy(getCurrentEntity()) onCopy(getCurrentEntity())
@@ -107,7 +107,7 @@ fun <T> RuleEditSheet(
} }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.paste_rule)) }, text = { AppText(stringResource(R.string.paste_rule)) },
leadingIcon = { Icon(Icons.Default.ContentPaste, null) }, leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
onClick = { onClick = {
scope.launch { scope.launch {
@@ -136,20 +136,20 @@ fun <T> RuleEditSheet(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = name, value = name,
onValueChange = { name = it }, onValueChange = { name = it },
label = { Text(stringResource(R.string.name)) }, label = { AppText(stringResource(R.string.name)) },
singleLine = true singleLine = true
) )
OutlinedTextField( OutlinedTextField(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = rule1, value = rule1,
onValueChange = { rule1 = it }, onValueChange = { rule1 = it },
label = { Text(label1) } label = { AppText(label1) }
) )
OutlinedTextField( OutlinedTextField(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = rule2, value = rule2,
onValueChange = { rule2 = it }, onValueChange = { rule2 = it },
label = { Text(label2) }, label = { AppText(label2) },
minLines = 3 minLines = 3
) )
} }
@@ -10,20 +10,12 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton 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.animateFloatingActionButton
import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -34,9 +26,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import io.legado.app.R import io.legado.app.R
import io.legado.app.ui.widget.components.ActionItem 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.SelectionActions
import io.legado.app.ui.widget.components.list.ListScaffold 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.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) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -49,7 +44,7 @@ fun <T> RuleListScaffold(
onSearchQueryChange: (String) -> Unit, onSearchQueryChange: (String) -> Unit,
searchPlaceholder: String = "搜索...", searchPlaceholder: String = "搜索...",
topBarActions: @Composable RowScope.() -> Unit = {}, topBarActions: @Composable RowScope.() -> Unit = {},
bottomContent: @Composable (ColumnScope.(TopAppBarScrollBehavior) -> Unit)? = null, bottomContent: @Composable (ColumnScope.(GlassTopAppBarScrollBehavior) -> Unit)? = null,
dropDownMenuContent: (@Composable ColumnScope.(dismiss: () -> Unit) -> Unit)? = null, dropDownMenuContent: (@Composable ColumnScope.(dismiss: () -> Unit) -> Unit)? = null,
onClearSelection: () -> Unit, onClearSelection: () -> Unit,
onSelectAll: () -> Unit, onSelectAll: () -> Unit,
@@ -59,22 +54,15 @@ fun <T> RuleListScaffold(
onAddClick: (() -> Unit)? = null, onAddClick: (() -> Unit)? = null,
floatingActionButton: @Composable () -> Unit = { floatingActionButton: @Composable () -> Unit = {
onAddClick?.let { onClick -> onAddClick?.let { onClick ->
TooltipBox( AppFloatingActionButton(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider( onClick = onClick,
TooltipAnchorPosition.Above modifier = Modifier.animateFloatingActionButton(
visible = state.selectedIds.isEmpty(),
alignment = Alignment.BottomEnd,
), ),
tooltip = { PlainTooltip { Text("添加") } }, tooltipText = "添加"
state = rememberTooltipState(),
) { ) {
FloatingActionButton( Icon(Icons.Default.Add, contentDescription = "Add")
modifier = Modifier.animateFloatingActionButton(
visible = state.selectedIds.isEmpty(),
alignment = Alignment.BottomEnd,
),
onClick = onClick
) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
} }
} }
}, },
@@ -86,8 +74,8 @@ fun <T> RuleListScaffold(
if (showDeleteConfirmDialog) { if (showDeleteConfirmDialog) {
AlertDialog( AlertDialog(
onDismissRequest = { showDeleteConfirmDialog = false }, onDismissRequest = { showDeleteConfirmDialog = false },
title = { Text(stringResource(R.string.delete)) }, title = { AppText(stringResource(R.string.delete)) },
text = { Text(stringResource(R.string.del_msg)) }, text = { AppText(stringResource(R.string.del_msg)) },
confirmButton = { confirmButton = {
OutlinedButton( OutlinedButton(
onClick = { onClick = {
@@ -98,12 +86,12 @@ fun <T> RuleListScaffold(
contentColor = MaterialTheme.colorScheme.error contentColor = MaterialTheme.colorScheme.error
) )
) { ) {
Text(stringResource(R.string.ok)) AppText(stringResource(R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = { showDeleteConfirmDialog = false }) { TextButton(onClick = { showDeleteConfirmDialog = false }) {
Text(stringResource(R.string.cancel)) AppText(stringResource(R.string.cancel))
} }
} }
) )
@@ -7,6 +7,10 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector 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 @Composable
fun ClickableSettingItem( fun ClickableSettingItem(
@@ -19,20 +23,30 @@ fun ClickableSettingItem(
trailingContent: (@Composable () -> Unit)? = null, trailingContent: (@Composable () -> Unit)? = null,
onClick: () -> Unit onClick: () -> Unit
) { ) {
SettingItem( val composeEngine = LegadoTheme.composeEngine
modifier = modifier, if (ThemeResolver.isMiuixEngine(composeEngine)) {
title = title, SuperArrow(
description = description, title = title,
option = option, summary = description,
imageVector = imageVector, insideMargin = BasicComponentDefaults.InsideMargin,
trailingContent = trailingContent ?: { onClick = onClick
Icon( )
imageVector = Icons.Default.ChevronRight, } else {
contentDescription = null, SettingItem(
tint = MaterialTheme.colorScheme.onSurfaceVariant modifier = modifier,
) title = title,
}, description = description,
onClick = onClick, option = option,
onLongClick = onLongClick imageVector = imageVector,
) trailingContent = trailingContent ?: {
Icon(
imageVector = Icons.Default.ChevronRight,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
},
onClick = onClick,
onLongClick = onLongClick
)
}
} }
@@ -13,7 +13,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue 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.button.SmallOutlinedIconButton
import io.legado.app.ui.widget.components.card.TextCard 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.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -66,7 +66,7 @@ fun CompactDropdownSettingItem(
dropdownMenu = { onDismiss -> dropdownMenu = { onDismiss ->
displayEntries.forEachIndexed { index, display -> displayEntries.forEachIndexed { index, display ->
RoundDropdownMenuItem( RoundDropdownMenuItem(
text = { Text(display) }, text = { AppText(display) },
onClick = { onClick = {
onValueChange(entryValues[index]) onValueChange(entryValues[index])
onDismiss() onDismiss()
@@ -1,15 +1,17 @@
package io.legado.app.ui.widget.components.settingItem package io.legado.app.ui.widget.components.settingItem
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Replay import androidx.compose.material.icons.filled.Replay
import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -21,7 +23,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.legado.app.R 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.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 @Composable
fun InputSettingItem( fun InputSettingItem(
@@ -31,6 +38,7 @@ fun InputSettingItem(
description: String? = null, description: String? = null,
onConfirm: (String) -> Unit onConfirm: (String) -> Unit
) { ) {
// 1. 状态统一提升到外部,两套引擎共用
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
val state = rememberTextFieldState(initialText = value) val state = rememberTextFieldState(initialText = value)
@@ -42,51 +50,104 @@ fun InputSettingItem(
} }
} }
SettingItem( val composeEngine = LegadoTheme.composeEngine
title = title,
description = description, if (ThemeResolver.isMiuixEngine(composeEngine)) {
option = value, Column(modifier = Modifier.fillMaxWidth()) {
expanded = expanded, BasicComponent(
onExpandChange = { expanded = it }, title = title,
expandContent = { summary = value,
TextField( onClick = { expanded = !expanded }
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
}
) )
Row( AnimatedVisibility(visible = expanded) {
modifier = Modifier.fillMaxWidth(), Column(
horizontalArrangement = Arrangement.End modifier = Modifier
) { .fillMaxWidth()
SmallTextButton( .padding(horizontal = 16.dp, vertical = 4.dp)
text = "默认", ) {
icon = Icons.Default.Replay, MiuixTextField(
onClick = { state = state,
state.edit { replace(0, length, defaultValue.toString()) } 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, } else {
onClick = { 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()) onConfirm(state.text.toString())
expanded = false 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
}
)
}
} }
} )
) }
} }
@@ -4,12 +4,16 @@ import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
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.widget.components.menuItem.RoundDropdownMenuItem 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 @Composable
fun DropdownListSettingItem( fun DropdownListSettingItem(
@@ -21,33 +25,62 @@ fun DropdownListSettingItem(
imageVector: ImageVector? = null, imageVector: ImageVector? = null,
onValueChange: (String) -> Unit onValueChange: (String) -> Unit
) { ) {
val currentEntry = displayEntries.getOrNull(entryValues.indexOf(selectedValue)) ?: selectedValue val composeEngine = LegadoTheme.composeEngine
SettingItem( if (ThemeResolver.isMiuixEngine(composeEngine)) {
title = title, val selectedIndex = entryValues.indexOf(selectedValue).coerceAtLeast(0)
description = description, val spinnerItems = displayEntries.map { display ->
option = currentEntry, SpinnerEntry(title = display)
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
)
}
} }
)
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
)
}
}
)
}
} }
@@ -19,7 +19,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf 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.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp 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.menuItem.RoundDropdownMenu
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -59,7 +60,7 @@ fun SettingItem(
var showMenu by remember { mutableStateOf(false) } var showMenu by remember { mutableStateOf(false) }
val isExpandable = expandContent != null && onExpandChange != null val isExpandable = expandContent != null && onExpandChange != null
GlassCard( SettingCard(
modifier = modifier modifier = modifier
.fillMaxWidth(), .fillMaxWidth(),
shape = shape, shape = shape,
@@ -101,25 +102,25 @@ fun SettingItem(
} }
} else null, } else null,
headlineContent = { headlineContent = {
Text( AppText(
text = title, text = title,
style = MaterialTheme.typography.titleMedium style = LegadoTheme.typography.titleMedium
) )
}, },
supportingContent = if (description != null || option != null) { supportingContent = if (description != null || option != null) {
{ {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
description?.let { description?.let {
Text( AppText(
it, it,
style = MaterialTheme.typography.bodySmallEmphasized, style = LegadoTheme.typography.bodySmallEmphasized,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f) color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
) )
} }
option?.let { option?.let {
Text( AppText(
it, it,
style = MaterialTheme.typography.labelMediumEmphasized, style = LegadoTheme.typography.labelMediumEmphasized,
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
} }
@@ -1,12 +1,15 @@
package io.legado.app.ui.widget.components.settingItem package io.legado.app.ui.widget.components.settingItem
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.TextFieldLineLimits 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.material.icons.filled.RestartAlt
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -29,7 +31,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp 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.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 @Composable
fun SliderSettingItem( fun SliderSettingItem(
@@ -45,85 +53,188 @@ fun SliderSettingItem(
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
var isInputMode 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()) val textFieldState = rememberTextFieldState(initialText = value.toInt().toString())
SettingItem( if (ThemeResolver.isMiuixEngine(composeEngine)) {
title = title,
color = color ?: MaterialTheme.colorScheme.surfaceContainerLow, Column(modifier = Modifier.fillMaxWidth()) {
option = description, BasicComponent(
expanded = expanded, title = title,
onExpandChange = { expanded = it }, summary = description,
expandContent = { onClick = { expanded = !expanded }
Row(verticalAlignment = Alignment.CenterVertically) { )
AnimatedContent(
targetState = isInputMode, AnimatedVisibility(visible = expanded) {
label = "input_slider_switch" Column(
) { targetInputMode -> modifier = Modifier
if (targetInputMode) { .fillMaxWidth()
TextField( .padding(horizontal = 16.dp, vertical = 8.dp)
state = textFieldState, ) {
lineLimits = TextFieldLineLimits.SingleLine, AnimatedContent(
label = { Text("输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})") }, targetState = isInputMode,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), label = "input_slider_switch"
modifier = Modifier ) { targetInputMode ->
.fillMaxWidth() if (targetInputMode) {
.heightIn(min = 48.dp), MiuixTextField(
contentPadding = PaddingValues( state = textFieldState,
top = 4.dp, lineLimits = TextFieldLineLimits.SingleLine,
bottom = 4.dp, label = "输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})",
start = 12.dp, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
end = 12.dp modifier = Modifier.fillMaxWidth(),
), inputTransformation = {
inputTransformation = { val newText = asCharSequence().toString()
val newText = asCharSequence().toString() newText.toFloatOrNull()?.let { num ->
newText.toFloatOrNull()?.let { num -> onValueChange(
onValueChange( num.coerceIn(
num.coerceIn( valueRange.start,
valueRange.start, valueRange.endInclusive
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()
)
}
}
)
}
}
)
}
} }
@@ -3,7 +3,12 @@ package io.legado.app.ui.widget.components.settingItem
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector 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 @Composable
fun SwitchSettingItem( fun SwitchSettingItem(
@@ -15,18 +20,40 @@ fun SwitchSettingItem(
enabled: Boolean = true, enabled: Boolean = true,
onCheckedChange: (Boolean) -> Unit onCheckedChange: (Boolean) -> Unit
) { ) {
SettingItem( val composeEngine = LegadoTheme.composeEngine
title = title,
description = description, if (ThemeResolver.isMiuixEngine(composeEngine)) {
imageVector = imageVector, val toggleAction = {
color = color, if (enabled) onCheckedChange(!checked)
onClick = { if (enabled) onCheckedChange(!checked) },
trailingContent = {
IconSwitch(
checked = checked,
onCheckedChange = onCheckedChange,
enabled = enabled
)
} }
)
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
)
}
)
}
} }
@@ -0,0 +1,63 @@
package io.legado.app.ui.widget.components.tabRow
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryScrollableTabRow
import androidx.compose.material3.Tab
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import io.legado.app.ui.theme.LegadoTheme
import io.legado.app.ui.theme.ThemeResolver
import io.legado.app.ui.widget.components.text.AppText
import top.yukonga.miuix.kmp.basic.TabRowDefaults
import top.yukonga.miuix.kmp.basic.TabRowWithContour
@Composable
fun AdaptiveTabRow(
tabTitles: List<String>,
selectedTabIndex: Int,
onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier
) {
val composeEngine = LegadoTheme.composeEngine
if (ThemeResolver.isMiuixEngine(composeEngine)) {
TabRowWithContour(
tabs = tabTitles,
selectedTabIndex = selectedTabIndex,
onTabSelected = onTabSelected,
modifier = modifier.padding(start = 12.dp),
colors = TabRowDefaults.tabRowColors(
backgroundColor = Color.Transparent
)
)
} else {
PrimaryScrollableTabRow(
selectedTabIndex = selectedTabIndex,
edgePadding = 0.dp,
divider = { },
containerColor = Color.Transparent,
minTabWidth = 0.dp,
modifier = modifier
) {
tabTitles.forEachIndexed { index, title ->
Tab(
selected = selectedTabIndex == index,
onClick = { onTabSelected(index) },
text = {
AppText(
text = title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(horizontal = 8.dp),
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
)
}
}
}
}
@@ -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
)
}
}

Some files were not shown because too many files have changed in this diff Show More