初始版本

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