diff --git a/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt b/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt index 59f0f1bb7..d1bc57845 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutScreen.kt @@ -15,7 +15,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -91,8 +90,6 @@ fun AboutScreen( .wrapContentWidth(Alignment.CenterHorizontally)) TextCard( text = versionName, - backgroundColor = colorScheme.tertiaryContainer, - contentColor = colorScheme.onTertiaryContainer, cornerRadius = 8.dp, modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt b/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt index ba3706e15..54bff48eb 100644 --- a/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt +++ b/app/src/main/java/io/legado/app/ui/about/AppLogSheet.kt @@ -31,7 +31,7 @@ import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.constant.AppLog import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.LogUtils import java.util.Date @@ -39,12 +39,14 @@ import java.util.Date @OptIn(ExperimentalMaterial3Api::class) @Composable fun AppLogSheet( + show: Boolean, onDismissRequest: () -> Unit ) { var logs by remember { mutableStateOf(AppLog.logs) } var showStackTrace by remember { mutableStateOf(null) } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Row( diff --git a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt b/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt index 025d24f01..496916e53 100644 --- a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt @@ -48,7 +48,6 @@ import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn import io.legado.app.ui.widget.components.lazylist.Scroller import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem -import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults import org.koin.androidx.compose.koinViewModel @@ -128,7 +127,7 @@ fun AllBookmarkScreen( onDismissRequest = { showMenu = false } ) { RoundDropdownMenuItem( - text = { AppText("导出 JSON") }, + text = "导出 JSON", onClick = { showMenu = false pendingExportIsMd = false @@ -136,7 +135,7 @@ fun AllBookmarkScreen( } ) RoundDropdownMenuItem( - text = { AppText("导出 Markdown") }, + text = "导出 Markdown", onClick = { showMenu = false pendingExportIsMd = true @@ -238,22 +237,21 @@ fun AllBookmarkScreen( } } - if (showBottomSheet && editingBookmark != null) { - BookmarkEditSheet( - bookmark = editingBookmark!!, - onDismiss = { - showBottomSheet = false - editingBookmark = null - }, - onSave = { updatedBookmark -> - viewModel.updateBookmark(updatedBookmark) - showBottomSheet = false - }, - onDelete = { bookmarkToDelete -> - viewModel.deleteBookmark(bookmarkToDelete) - showBottomSheet = false - } - ) - } + BookmarkEditSheet( + show = showBottomSheet && editingBookmark != null, + bookmark = editingBookmark ?: Bookmark(), + onDismiss = { + showBottomSheet = false + editingBookmark = null + }, + onSave = { updatedBookmark -> + viewModel.updateBookmark(updatedBookmark) + showBottomSheet = false + }, + onDelete = { bookmarkToDelete -> + viewModel.deleteBookmark(bookmarkToDelete) + showBottomSheet = false + } + ) } } diff --git a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt index 3f494c6f4..8700c3211 100644 --- a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt @@ -90,7 +90,7 @@ import io.legado.app.ui.widget.components.card.TextCard import io.legado.app.ui.widget.components.cover.Cover import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults @@ -180,112 +180,111 @@ fun ExploreShowScreen( } } - if (showGridCountSheet) { - GlassModalBottomSheet( + AppModalBottomSheet( + show = showGridCountSheet, + modifier = Modifier + .padding(16.dp), + onDismissRequest = { showGridCountSheet = false } + ) { + Row( modifier = Modifier - .padding(16.dp), - onDismissRequest = { showGridCountSheet = false } + .fillMaxWidth() + .padding(bottom = 16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 16.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - AppText( - text = "布局列数", - style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold) - ) - - Spacer(modifier = Modifier.width(12.dp)) - - TextCard( - text = "$gridColumnCount 列", - textStyle = LegadoTheme.typography.titleSmall, - verticalPadding = 4.dp, - horizontalPadding = 12.dp, - cornerRadius = 12.dp - ) - } - - Slider( - value = gridColumnCount.toFloat(), - onValueChange = { - val col = it.toInt().coerceIn(1, 10) - viewModel.saveGridCount(col) - }, - valueRange = 1f..10f, - steps = 8, - modifier = Modifier.padding(horizontal = 20.dp) + AppText( + text = "布局列数", + style = LegadoTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold) ) - Spacer(Modifier.height(24.dp)) + Spacer(modifier = Modifier.width(12.dp)) - OutlinedButton( - onClick = { showGridCountSheet = false }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - ) { - AppText("完成") - } + TextCard( + text = "$gridColumnCount 列", + textStyle = LegadoTheme.typography.titleSmall, + verticalPadding = 4.dp, + horizontalPadding = 12.dp, + cornerRadius = 12.dp + ) + } + + Slider( + value = gridColumnCount.toFloat(), + onValueChange = { + val col = it.toInt().coerceIn(1, 10) + viewModel.saveGridCount(col) + }, + valueRange = 1f..10f, + steps = 8, + modifier = Modifier.padding(horizontal = 20.dp) + ) + + Spacer(Modifier.height(24.dp)) + + OutlinedButton( + onClick = { showGridCountSheet = false }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + AppText("完成") } } - if (showKindSheet) { - GlassModalBottomSheet( - onDismissRequest = { showKindSheet = false } - ) { - var kindQuery by remember { mutableStateOf("") } + AppModalBottomSheet( + show = showKindSheet, + onDismissRequest = { showKindSheet = false } + ) { - SearchBarSection( - query = kindQuery, - backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh, - onQueryChange = { kindQuery = it }, - placeholder = "选择或搜索分类", - ) + var kindQuery by remember { mutableStateOf("") } - val filteredKinds = remember(kindQuery, kinds) { - if (kindQuery.isBlank()) kinds - else kinds.filter { kind -> - kind.title.contains(kindQuery, ignoreCase = true) || - (kind.url?.contains(kindQuery, ignoreCase = true) == true) - } + SearchBarSection( + query = kindQuery, + backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh, + onQueryChange = { kindQuery = it }, + placeholder = "选择或搜索分类", + ) + + val filteredKinds = remember(kindQuery, kinds) { + if (kindQuery.isBlank()) kinds + else kinds.filter { kind -> + kind.title.contains(kindQuery, ignoreCase = true) || + (kind.url?.contains(kindQuery, ignoreCase = true) == true) } + } - LazyVerticalGrid( - columns = GridCells.Fixed(3), - contentPadding = PaddingValues(16.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier.weight(1f, fill = false) - ) { - itemsIndexed( - items = filteredKinds, - key = { index, kind -> "${kind.url ?: kind.title}_$index" }, - span = { _, kind -> - val isClickable = !kind.url.isNullOrBlank() - if (isClickable) GridItemSpan(1) else GridItemSpan(3) + LazyVerticalGrid( + columns = GridCells.Fixed(3), + contentPadding = PaddingValues(16.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.weight(1f, fill = false) + ) { + itemsIndexed( + items = filteredKinds, + key = { index, kind -> "${kind.url ?: kind.title}_$index" }, + span = { _, kind -> + val isClickable = !kind.url.isNullOrBlank() + if (isClickable) GridItemSpan(1) else GridItemSpan(3) + } + ) { _, kind -> + KindGridItem( + modifier = Modifier.animateItem(), + kind = kind, + currentTitle = selectedTitle ?: title, + onClick = { + showKindSheet = false + viewModel.switchExploreUrl(kind) } - ) { _, kind -> - KindGridItem( - modifier = Modifier.animateItem(), - kind = kind, - currentTitle = selectedTitle ?: title, - onClick = { - showKindSheet = false - viewModel.switchExploreUrl(kind) - } - ) - } + ) } - } } + AppScaffold( modifier = Modifier .nestedScroll(scrollBehavior.nestedScrollConnection), @@ -339,7 +338,7 @@ fun ExploreShowScreen( onDismissRequest = { showMenu = false } ) { RoundDropdownMenuItem( - text = { AppText("全部显示") }, + text = "全部显示", onClick = { viewModel.setFilterState(BookFilterState.SHOW_ALL) showMenu = false @@ -351,7 +350,7 @@ fun ExploreShowScreen( ) RoundDropdownMenuItem( - text = { AppText("隐藏已在书架的同源书籍") }, + text = "隐藏已在书架的同源书籍", onClick = { viewModel.setFilterState(BookFilterState.HIDE_IN_SHELF) showMenu = false @@ -363,7 +362,7 @@ fun ExploreShowScreen( ) RoundDropdownMenuItem( - text = { AppText("隐藏已在书架的非同源书籍") }, + text = "隐藏已在书架的非同源书籍", onClick = { viewModel.setFilterState(BookFilterState.HIDE_SAME_NAME_AUTHOR) showMenu = false @@ -375,7 +374,7 @@ fun ExploreShowScreen( ) RoundDropdownMenuItem( - text = { AppText("只显示不在书架的书籍") }, + text = "只显示不在书架的书籍", onClick = { viewModel.setFilterState(BookFilterState.SHOW_NOT_IN_SHELF_ONLY) showMenu = false diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt index 472ce06ee..f10bfccab 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/book/group/GroupEditSheet.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -36,9 +35,8 @@ import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.alert -import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.cover.Cover -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem import io.legado.app.ui.widget.components.text.AppText @@ -55,11 +53,12 @@ import java.io.FileOutputStream @OptIn(ExperimentalMaterial3Api::class) @Composable fun GroupEditSheet( + show: Boolean, group: BookGroup? = null, onDismissRequest: () -> Unit, viewModel: GroupViewModel = koinViewModel() ) { - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet(show = show, onDismissRequest = onDismissRequest) { GroupEditContent( group = group, onDismissRequest = onDismissRequest, @@ -108,17 +107,9 @@ fun GroupEditContent( Column( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(bottom = 16.dp) .verticalScroll(rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, ) { - AppText( - text = stringResource(R.string.group_edit), - style = LegadoTheme.typography.titleLarge, - modifier = Modifier.padding(vertical = 16.dp) - ) - Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.Top, diff --git a/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt b/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt index 3f0588aee..6a34fa1a3 100644 --- a/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookScreen.kt @@ -88,7 +88,7 @@ import io.legado.app.ui.widget.components.button.SmallTonalIconButton import io.legado.app.ui.widget.components.card.TextCard import io.legado.app.ui.widget.components.list.ListScaffold import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.ArchiveUtils import io.legado.app.utils.ConvertUtils @@ -199,42 +199,41 @@ fun RemoteBookScreen( } } - if (showSheet != null) { - GlassModalBottomSheet( - onDismissRequest = { showSheet = null } - ) { - when (val state = showSheet) { - is RemoteBookSheet.Servers -> { - ServersSheetContent( - servers = uiState.servers, - selectedServerId = uiState.selectedServerId, - onSelect = { - viewModel.selectServer(it) - showSheet = null - }, - onEdit = { showSheet = RemoteBookSheet.ServerConfig(it) }, - onDelete = { viewModel.deleteServer(it) }, - onAdd = { showSheet = RemoteBookSheet.ServerConfig(null) }, - onDefault = { - viewModel.selectServer(AppConst.DEFAULT_WEBDAV_ID) - showSheet = null - } - ) - } - - is RemoteBookSheet.ServerConfig -> { - ServerConfigSheetContent( - server = state.server, - onSave = { - viewModel.saveServer(it) - showSheet = RemoteBookSheet.Servers - }, - onCancel = { showSheet = RemoteBookSheet.Servers } - ) - } - - else -> {} + AppModalBottomSheet( + show = showSheet != null, + onDismissRequest = { showSheet = null } + ) { + when (val state = showSheet) { + is RemoteBookSheet.Servers -> { + ServersSheetContent( + servers = uiState.servers, + selectedServerId = uiState.selectedServerId, + onSelect = { + viewModel.selectServer(it) + showSheet = null + }, + onEdit = { showSheet = RemoteBookSheet.ServerConfig(it) }, + onDelete = { viewModel.deleteServer(it) }, + onAdd = { showSheet = RemoteBookSheet.ServerConfig(null) }, + onDefault = { + viewModel.selectServer(AppConst.DEFAULT_WEBDAV_ID) + showSheet = null + } + ) } + + is RemoteBookSheet.ServerConfig -> { + ServerConfigSheetContent( + server = state.server, + onSave = { + viewModel.saveServer(it) + showSheet = RemoteBookSheet.Servers + }, + onCancel = { showSheet = RemoteBookSheet.Servers } + ) + } + + else -> {} } } @@ -260,7 +259,7 @@ fun RemoteBookScreen( }, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText("按名称排序") }, + text = "按名称排序", onClick = { viewModel.toggleSort(RemoteBookSort.Name) dismiss() @@ -272,7 +271,7 @@ fun RemoteBookScreen( } ) RoundDropdownMenuItem( - text = { AppText("按时间排序") }, + text = "按时间排序", onClick = { viewModel.toggleSort(RemoteBookSort.Default) dismiss() diff --git a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt b/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt index 3263ec78d..56314ad97 100644 --- a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt @@ -32,13 +32,9 @@ import androidx.compose.material.icons.filled.Schedule import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Timeline import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -78,13 +74,14 @@ import cn.hutool.core.date.DateUtil import io.legado.app.data.entities.readRecord.ReadRecord import io.legado.app.data.entities.readRecord.ReadRecordDetail import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.AnimatedTextLine +import io.legado.app.ui.widget.CollapsibleHeader import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.EmptyMessageView import io.legado.app.ui.widget.components.SearchBarSection -import io.legado.app.ui.widget.components.SectionHeader import io.legado.app.ui.widget.components.button.AlertButton +import io.legado.app.ui.widget.components.button.AppIconButton import io.legado.app.ui.widget.components.button.TopbarNavigationButton +import io.legado.app.ui.widget.components.card.GlassCard import io.legado.app.ui.widget.components.cover.Cover import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarTopBar import io.legado.app.ui.widget.components.heatmap.HeatmapConfig @@ -96,9 +93,11 @@ import io.legado.app.ui.widget.components.heatmap.WeekdayLabelsColumn import io.legado.app.ui.widget.components.heatmap.rememberDateRange import io.legado.app.ui.widget.components.heatmap.rememberDaysInRange import io.legado.app.ui.widget.components.heatmap.rememberWeeks -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.icon.AppIcon +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.swipe.SwipeAction import io.legado.app.ui.widget.components.swipe.SwipeActionContainer +import io.legado.app.ui.widget.components.text.AnimatedTextLine import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults @@ -164,7 +163,7 @@ fun ReadRecordScreen( TopbarNavigationButton(onClick = onBackClick) }, actions = { - IconButton(onClick = { + AppIconButton(onClick = { val newMode = when (displayMode) { DisplayMode.AGGREGATE -> DisplayMode.TIMELINE DisplayMode.TIMELINE -> DisplayMode.LATEST @@ -178,13 +177,16 @@ fun ReadRecordScreen( DisplayMode.LATEST -> Icons.AutoMirrored.Filled.List } val description = if (displayMode == DisplayMode.AGGREGATE) "Switch to Timeline" else "Switch to Aggregate" - Icon(icon, description) + AppIcon(icon, description) } - IconButton(onClick = { showCalendar = !showCalendar }) { - Icon(Icons.Default.CalendarMonth, contentDescription = "Toggle Calendar") + AppIconButton(onClick = { showCalendar = !showCalendar }) { + AppIcon( + Icons.Default.CalendarMonth, + contentDescription = "Toggle Calendar" + ) } - IconButton(onClick = { showSearch = !showSearch }) { - Icon(Icons.Default.Search, contentDescription = null) + AppIconButton(onClick = { showSearch = !showSearch }) { + AppIcon(Icons.Default.Search, contentDescription = null) } }, scrollBehavior = scrollBehavior @@ -314,24 +316,23 @@ fun ReadRecordScreen( ) } - if (showCalendar) { - GlassModalBottomSheet( - onDismissRequest = { showCalendar = false } - ) { - HeatmapCalendarSection( - dailyReadCounts = state.dailyReadCounts, - dailyReadTimes = state.dailyReadTimes, - selectedDate = state.selectedDate, - onDateSelected = { date -> - viewModel.setSelectedDate(date) - showCalendar = false - }, - onClearDate = { - viewModel.setSelectedDate(null) - showCalendar = false - } - ) - } + AppModalBottomSheet( + show = showCalendar, + onDismissRequest = { showCalendar = false } + ) { + HeatmapCalendarSection( + dailyReadCounts = state.dailyReadCounts, + dailyReadTimes = state.dailyReadTimes, + selectedDate = state.selectedDate, + onDateSelected = { date -> + viewModel.setSelectedDate(date) + showCalendar = false + }, + onClearDate = { + viewModel.setSelectedDate(null) + showCalendar = false + } + ) } @@ -869,28 +870,27 @@ fun DateHeader( date: String, dailyTotalTime: Long? = null ) { - val dateText = formatFriendlyDate(date) - SectionHeader( + CollapsibleHeader( + showIcon = false, + isCollapsed = false, + onToggle = { }, + title = "", titleContent = { - Column { + val dateText = formatFriendlyDate(date) + AppText( + text = dateText, + style = LegadoTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + color = LegadoTheme.colorScheme.primary + ) + dailyTotalTime?.let { total -> AppText( - text = dateText, - style = LegadoTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.secondary + text = "已读 ${formatDuring(total)}", + style = LegadoTheme.typography.bodySmall, + color = LegadoTheme.colorScheme.onSurface ) - - dailyTotalTime?.let { total -> - AppText( - text = "已读 ${formatDuring(total)}", - style = LegadoTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurface - ) - } } - }, - detailContent = null, - horizontalArrangement = Arrangement.Start + } ) } @@ -912,14 +912,12 @@ fun ReadingSummaryCard( val totalDurationMinutes = totalTimeMillis / 60000 - Card( + GlassCard( onClick = onClick, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surfaceContainer - ) + containerColor = LegadoTheme.colorScheme.surfaceContainer ) { Row( modifier = Modifier @@ -934,7 +932,7 @@ fun ReadingSummaryCard( AppText( text = title, style = LegadoTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.primary + color = LegadoTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(4.dp)) @@ -947,7 +945,7 @@ fun ReadingSummaryCard( AppText( text = "$bookCount", style = LegadoTheme.typography.headlineMedium, - color = MaterialTheme.colorScheme.primary, + color = LegadoTheme.colorScheme.primary, fontWeight = FontWeight.Bold, ) AppText( @@ -965,7 +963,7 @@ fun ReadingSummaryCard( AppText( text = "共阅读 $timeString", style = LegadoTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant + color = LegadoTheme.colorScheme.onSurfaceVariant ) } diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt index 813129e82..ff6d87a8c 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt @@ -310,7 +310,7 @@ fun SearchHistoryList( AppText( text = "搜索历史", style = LegadoTheme.typography.titleSmallEmphasized, - color = MaterialTheme.colorScheme.primary, + color = LegadoTheme.colorScheme.primary, modifier = Modifier.align(Alignment.Center) ) SmallAnimatedActionButton( diff --git a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt index b1ede3b7d..a737a4e70 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt @@ -313,33 +313,33 @@ fun TocScreen( when (pagerState.currentPage) { 0 -> { RoundDropdownMenuItem( - text = { AppText("使用替换规则") }, + text = "使用替换规则", trailingIcon = { Checkbox(checked = useReplace, onCheckedChange = null) }, onClick = { viewModel.toggleUseReplace() } ) RoundDropdownMenuItem( - text = { AppText("显示字数") }, + text = "显示字数", trailingIcon = { Checkbox(checked = showWordCount, onCheckedChange = null) }, onClick = { viewModel.toggleShowWordCount() } ) RoundDropdownMenuItem( - text = { AppText("反转目录") }, + text = "反转目录", onClick = { viewModel.reverseToc() } ) PillDivider() RoundDropdownMenuItem( - text = { AppText("替换规则") }, + text = "替换规则", onClick = { onOpenReplaceRule(null) dismiss() } ) RoundDropdownMenuItem( - text = { AppText("新建替换规则") }, + text = "新建替换规则", onClick = { val scopes = mutableListOf() book?.name?.let { scopes.add(it) } @@ -359,7 +359,7 @@ fun TocScreen( if (book?.isLocal == true) { PillHeaderDivider(title = "本地书籍选项") RoundDropdownMenuItem( - text = { AppText("本地书籍目录规则") }, + text = "本地书籍目录规则", onClick = { val intent = Intent(context, TxtTocRuleActivity::class.java).apply { @@ -370,7 +370,7 @@ fun TocScreen( } ) RoundDropdownMenuItem( - text = { AppText("拆分超长章节") }, + text = "拆分超长章节", trailingIcon = { Checkbox( checked = viewModel.isSplitLongChapter, @@ -387,7 +387,7 @@ fun TocScreen( else -> { RoundDropdownMenuItem( - text = { AppText("导出书签为JSON") }, + text = "导出书签为JSON", onClick = { val dateFormat = SimpleDateFormat( "yyyyMMdd_HHmm", @@ -399,7 +399,7 @@ fun TocScreen( } ) RoundDropdownMenuItem( - text = { AppText("导出书签为MarkDown") }, + text = "导出书签为MarkDown", onClick = { val dateFormat = SimpleDateFormat( "yyyyMMdd_HHmm", @@ -465,13 +465,13 @@ fun TocScreen( onDismissRequest = { showVolumeMenu = false } ) { RoundDropdownMenuItem( - text = { AppText("展开所有卷") }, + text = "展开所有卷", onClick = { viewModel.expandAllVolumes(); showVolumeMenu = false } ) RoundDropdownMenuItem( - text = { AppText("收起所有卷") }, + text = "收起所有卷", onClick = { viewModel.collapseAllVolumes(); showVolumeMenu = false } @@ -483,7 +483,7 @@ fun TocScreen( PillHeaderDivider(title = "快速跳转") volumeItems.forEach { uiItem -> RoundDropdownMenuItem( - text = { AppText(uiItem.title) }, + text = uiItem.title, onClick = { scope.launch { val targetIndex = @@ -594,20 +594,19 @@ fun TocScreen( } } - if (editingBookmark != null) { - BookmarkEditSheet( - bookmark = editingBookmark!!, - onDismiss = { editingBookmark = null }, - onSave = { updatedBookmark -> - viewModel.updateBookmark(updatedBookmark) - editingBookmark = null - }, - onDelete = { bookmarkToDelete -> - viewModel.deleteBookmark(bookmarkToDelete) - editingBookmark = null - } - ) - } + BookmarkEditSheet( + show = editingBookmark != null, + bookmark = editingBookmark!!, + onDismiss = { editingBookmark = null }, + onSave = { updatedBookmark -> + viewModel.updateBookmark(updatedBookmark) + editingBookmark = null + }, + onDelete = { bookmarkToDelete -> + viewModel.deleteBookmark(bookmarkToDelete) + editingBookmark = null + } + ) } } diff --git a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt index dd17674c4..02d004f74 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt @@ -5,7 +5,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -44,13 +43,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.legado.app.R import io.legado.app.base.BaseRuleEvent import io.legado.app.data.entities.TxtTocRule -import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.ActionItem import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.button.SmallIconButton import io.legado.app.ui.widget.components.card.ReorderableSelectionItem import io.legado.app.ui.widget.components.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.importComponents.BaseImportUiState import io.legado.app.ui.widget.components.importComponents.BatchImportDialog import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn @@ -154,54 +151,49 @@ fun TxtRuleScreen( ) } - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - title = stringResource(R.string.export), - onSelectSysDir = { - showExportSheet = false - exportDoc.launch("exportDictRule.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + title = stringResource(R.string.export), + onSelectSysDir = { + showExportSheet = false + exportDoc.launch("exportDictRule.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_txt_toc_rule), - onSelectSysFile = { types -> - importDoc.launch(types) - showImportSheet = false - }, - onManualInput = { - showUrlInput = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = "导入词典规则", - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - itemContent = { rule, _ -> - Column { - AppText(rule.name, style = LegadoTheme.typography.titleMedium) - AppText(rule.rule, style = LegadoTheme.typography.bodySmall, maxLines = 1) - } - } - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_txt_toc_rule), + onSelectSysFile = { types -> + importDoc.launch(types) + showImportSheet = false + }, + onManualInput = { + showUrlInput = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) + + BatchImportDialog( + title = "导入词典规则", + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + itemTitle = { rule -> rule.name }, + itemSubtitle = { rule -> + rule.rule.takeIf { it.isNotBlank() } + } + ) LaunchedEffect(reorderableState.isAnyItemDragging) { if (!reorderableState.isAnyItemDragging) { @@ -229,48 +221,47 @@ fun TxtRuleScreen( ) } - if (showEditSheet) { - RuleEditSheet( - rule = editingRule, - title = stringResource(R.string.txt_toc_rule), - label1 = stringResource(R.string.regex), - label2 = stringResource(R.string.example), - onDismissRequest = { - showEditSheet = false - editingRule = null - }, - onSave = { updatedRule -> - //TODO:我很想把他改为自增主键,但为了兼容性日后再说 - if (editingRule == null) { - viewModel.insert(updatedRule) - } else { - viewModel.update(updatedRule) - } - showEditSheet = false - editingRule = null - }, - onCopy = { viewModel.copyRule(it) }, - onPaste = { viewModel.pasteRule() }, - toFields = { r -> - RuleEditFields( - name = r?.name ?: "", - rule1 = r?.rule ?: "", - rule2 = r?.example ?: "" - ) - }, - fromFields = { fields, old -> - old?.copy( - name = fields.name, - rule = fields.rule1, - example = fields.rule2 - ) ?: TxtTocRule( - name = fields.name, - rule = fields.rule1, - example = fields.rule2 - ) + RuleEditSheet( + show = showEditSheet, + rule = editingRule, + title = stringResource(R.string.txt_toc_rule), + label1 = stringResource(R.string.regex), + label2 = stringResource(R.string.example), + onDismissRequest = { + showEditSheet = false + editingRule = null + }, + onSave = { updatedRule -> + //TODO:我很想把他改为自增主键,但为了兼容性日后再说 + if (editingRule == null) { + viewModel.insert(updatedRule) + } else { + viewModel.update(updatedRule) } - ) - } + showEditSheet = false + editingRule = null + }, + onCopy = { viewModel.copyRule(it) }, + onPaste = { viewModel.pasteRule() }, + toFields = { r -> + RuleEditFields( + name = r?.name ?: "", + rule1 = r?.rule ?: "", + rule2 = r?.example ?: "" + ) + }, + fromFields = { fields, old -> + old?.copy( + name = fields.name, + rule = fields.rule1, + example = fields.rule2 + ) ?: TxtTocRule( + name = fields.name, + rule = fields.rule1, + example = fields.rule2 + ) + } + ) RuleListScaffold( title = if (isPickMode) "选择目录规则" else "目录规则", @@ -312,7 +303,7 @@ fun TxtRuleScreen( snackbarHostState = snackbarHostState, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_str)) }, + text = stringResource(R.string.import_str), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) diff --git a/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt index e261c97d0..7bd26ad3b 100644 --- a/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/backupConfig/BackupConfigScreen.kt @@ -453,31 +453,30 @@ fun BackupConfigScreen( ) } - if (showBackupFilePicker) { - FilePickerSheet( - onDismissRequest = { showBackupFilePicker = false }, - onSelectSysDir = { - showBackupFilePicker = false - try { - selectBackupPathLauncher.launch(null) - } catch (e: Exception) { - } + FilePickerSheet( + show = showBackupFilePicker, + onDismissRequest = { showBackupFilePicker = false }, + onSelectSysDir = { + showBackupFilePicker = false + try { + selectBackupPathLauncher.launch(null) + } catch (e: Exception) { } - ) - } + } + ) - if (showRestoreFilePicker) { - FilePickerSheet( - onDismissRequest = { showRestoreFilePicker = false }, - onSelectSysDir = { - showRestoreFilePicker = false - try { - backupAndSelectLauncher.launch(null) - } catch (e: Exception) { - } + + FilePickerSheet( + show = showRestoreFilePicker, + onDismissRequest = { showRestoreFilePicker = false }, + onSelectSysDir = { + showRestoreFilePicker = false + try { + backupAndSelectLauncher.launch(null) + } catch (e: Exception) { } - ) - } + } + ) if (showRestoreSheet && backupNames.isNotEmpty()) { AlertDialog( diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt index 829901a72..e34790879 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverConfigScreen.kt @@ -246,17 +246,17 @@ fun CoverConfigScreen( } } - if (showCoverRuleSheet) { - CoverRuleConfigSheet(onDismissRequest = { showCoverRuleSheet = false }) - } + CoverRuleConfigSheet( + show = showCoverRuleSheet, + onDismissRequest = { showCoverRuleSheet = false } + ) - manageKey?.let { key -> - CoverManageSheet( - preferenceKey = key, - onDismissRequest = { manageKey = null }, - viewModel = viewModel - ) - } + CoverManageSheet( + show = manageKey != null, + preferenceKey = manageKey!!, + onDismissRequest = { manageKey = null }, + viewModel = viewModel + ) showColorPickerByField?.let { field -> val initialColor = when (field) { @@ -268,6 +268,7 @@ fun CoverConfigScreen( } ColorPickerSheet( + show = showColorPickerByField != null, initialColor = initialColor, onDismissRequest = { showColorPickerByField = null }, onColorSelected = { color -> diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt index 7f28526ad..6fc5536d0 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverManageSheet.kt @@ -37,12 +37,13 @@ import io.legado.app.R import io.legado.app.constant.PreferKey import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun CoverManageSheet( + show: Boolean, preferenceKey: String, onDismissRequest: () -> Unit, viewModel: CoverConfigViewModel @@ -62,7 +63,8 @@ fun CoverManageSheet( } val coverList = currentCovers.split(",").filter { it.isNotBlank() } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( @@ -142,14 +144,13 @@ fun CoverManageSheet( } } - if (showFilePicker) { - FilePickerSheet( - onDismissRequest = { showFilePicker = false }, - onSelectSysFiles = { - selectImages.launch("image/*") - showFilePicker = false - }, - allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") - ) - } + FilePickerSheet( + show = showFilePicker, + onDismissRequest = { showFilePicker = false }, + onSelectSysFiles = { + selectImages.launch("image/*") + showFilePicker = false + }, + allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") + ) } diff --git a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt index 56b5ceb74..0833f6f07 100644 --- a/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/coverConfig/CoverRuleConfigSheet.kt @@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.model.BookCover import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.InputSettingItem import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.toastOnUi @@ -36,6 +36,7 @@ import splitties.init.appCtx @OptIn(ExperimentalMaterial3Api::class) @Composable fun CoverRuleConfigSheet( + show: Boolean, onDismissRequest: () -> Unit ) { var enable by remember { mutableStateOf(false) } @@ -51,7 +52,8 @@ fun CoverRuleConfigSheet( coverRule = rule.coverRule } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt index 6be30bb24..e01b733c5 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/CheckSourceBottomSheet.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import io.legado.app.ui.widget.components.text.AppText import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -21,19 +20,22 @@ import io.legado.app.R import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.checkBox.CheckboxGroupContainer import io.legado.app.ui.widget.components.checkBox.CheckboxItem -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.SliderSettingItem +import io.legado.app.ui.widget.components.text.AppText import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun CheckSourceBottomSheet( + show: Boolean, viewModel: OtherConfigViewModel = koinViewModel(), onDismiss: () -> Unit ) { val context = LocalContext.current - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismiss ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt index ac5fdd38c..075cb3a89 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt @@ -42,7 +42,7 @@ import io.legado.app.help.DirectLinkUpload import io.legado.app.lib.dialogs.selector import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.checkBox.CheckboxItem -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject @@ -53,6 +53,7 @@ import io.legado.app.utils.toastOnUi @OptIn(ExperimentalMaterial3Api::class) @Composable fun DirectLinkUploadBottomSheet( + show: Boolean, viewModel: OtherConfigViewModel, onDismiss: () -> Unit ) { @@ -64,7 +65,8 @@ fun DirectLinkUploadBottomSheet( viewModel.initDirectLinkRule() } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismiss ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt index a86a882fa..413de582f 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt @@ -398,33 +398,30 @@ fun OtherConfigScreen( } } - if (showFilePicker) { - FilePickerSheet( - onDismissRequest = { showFilePicker = false }, - onSelectSysDir = { - showFilePicker = false - try { - selectDocTree.launch(null) - } catch (e: Exception) { + FilePickerSheet( + show = showFilePicker, + onDismissRequest = { showFilePicker = false }, + onSelectSysDir = { + showFilePicker = false + try { + selectDocTree.launch(null) + } catch (e: Exception) { - } } - ) - } + } + ) - if (showCheckSourceSheet) { - CheckSourceBottomSheet( - viewModel = viewModel, - onDismiss = { showCheckSourceSheet = false } - ) - } + CheckSourceBottomSheet( + show = showCheckSourceSheet, + viewModel = viewModel, + onDismiss = { showCheckSourceSheet = false } + ) - if (showDirectLinkUploadSheet) { - DirectLinkUploadBottomSheet( - viewModel = viewModel, - onDismiss = { showDirectLinkUploadSheet = false } - ) - } + DirectLinkUploadBottomSheet( + show = showDirectLinkUploadSheet, + viewModel = viewModel, + onDismiss = { showDirectLinkUploadSheet = false } + ) if (showClearCacheDialog) { ConfirmDialog( diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt index fe143678f..52b6d9888 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/PageKeySheet.kt @@ -23,18 +23,19 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun PageKeySheet( + show: Boolean, onDismissRequest: () -> Unit ) { var prevKeys by remember { mutableStateOf(ReadConfig.prevKeys) } var nextKeys by remember { mutableStateOf(ReadConfig.nextKeys) } - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet(show = show, onDismissRequest = onDismissRequest) { Column( modifier = Modifier.Companion .fillMaxWidth() diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt index ebe4e064e..9b9456f36 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt @@ -320,7 +320,8 @@ fun ReadConfigScreen( } } - if (showPageKeySheet) { - PageKeySheet(onDismissRequest = { showPageKeySheet = false }) - } + PageKeySheet( + show = showPageKeySheet, + onDismissRequest = { showPageKeySheet = false } + ) } diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt index 2f19eb534..e1a95bff2 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/BackgroundImageManageSheet.kt @@ -32,7 +32,7 @@ import coil.compose.AsyncImage import io.legado.app.R import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -40,6 +40,7 @@ import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun BackgroundImageManageSheet( + show: Boolean, isDarkTheme: Boolean, onDismissRequest: () -> Unit, viewModel: ThemeConfigViewModel = koinViewModel() @@ -65,7 +66,8 @@ fun BackgroundImageManageSheet( ThemeConfig.bgImageLight } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( @@ -140,14 +142,13 @@ fun BackgroundImageManageSheet( } } - if (showFilePicker) { - FilePickerSheet( - onDismissRequest = { showFilePicker = false }, - onSelectSysFile = { - selectImage.launch("image/*") - showFilePicker = false - }, - allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") - ) - } + FilePickerSheet( + show = showFilePicker, + onDismissRequest = { showFilePicker = false }, + onSelectSysFile = { + selectImage.launch("image/*") + showFilePicker = false + }, + allowExtensions = arrayOf("jpg", "jpeg", "png", "webp") + ) } diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt index e273691ec..045d7fd84 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/LauncherIconPickerSheet.kt @@ -39,7 +39,7 @@ import io.legado.app.ui.main.Launcher5 import io.legado.app.ui.main.Launcher6 import io.legado.app.ui.main.LauncherW import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.getCompatDrawable import splitties.init.appCtx @@ -47,6 +47,7 @@ import splitties.init.appCtx @OptIn(ExperimentalMaterial3Api::class) @Composable fun LauncherIconPickerSheet( + show: Boolean, selectedValue: String, onDismissRequest: () -> Unit, onValueChange: (String) -> Unit @@ -54,7 +55,8 @@ fun LauncherIconPickerSheet( val context = LocalContext.current val icons = LauncherIcons.list - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt index 2902d9631..4bcec4533 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfig.kt @@ -15,14 +15,14 @@ object ThemeConfig { var enableBlur by prefDelegate(PreferKey.enableBlur, false) - var enableProgressiveBlur by prefDelegate(PreferKey.enableProgressiveBlur, true) + var enableProgressiveBlur by prefDelegate(PreferKey.enableProgressiveBlur, false) var useFlexibleTopAppBar by prefDelegate(PreferKey.useFlexibleTopAppBar, true) var paletteStyle by prefDelegate(PreferKey.paletteStyle, "tonalSpot") //m3 or miuix - var composeEngine by prefDelegate(PreferKey.composeEngine, "m3") + var composeEngine by prefDelegate(PreferKey.composeEngine, "material") var materialVersion by prefDelegate(PreferKey.materialVersion, "material3") diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt index a3163414a..1047c885a 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeConfigScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -44,6 +45,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.ToggleButton import androidx.compose.material3.ToggleButtonDefaults @@ -95,6 +97,10 @@ import io.legado.app.utils.postEvent import io.legado.app.utils.restart import io.legado.app.utils.toastOnUi import org.koin.androidx.compose.koinViewModel +import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.Card as MiuixCard +import top.yukonga.miuix.kmp.basic.CardDefaults as MiuixCardDefaults +import top.yukonga.miuix.kmp.basic.Text as MiuixText @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable @@ -137,9 +143,10 @@ fun ThemeConfigScreen( .verticalScroll(rememberScrollState()) .padding(16.dp) ) { - val composeEngine = remember { ThemeConfig.composeEngine } - val isMiuixEngine = - remember(composeEngine) { ThemeResolver.isMiuixEngine(composeEngine) } + val composeEngine = ThemeConfig.composeEngine + val isMiuixEngine = remember(composeEngine) { + ThemeResolver.isMiuixEngine(composeEngine) + } val isDarkTheme = when (selectedThemeMode) { "1" -> false "2" -> true @@ -169,6 +176,20 @@ fun ThemeConfigScreen( themeItems.zip(themeValues).toList() } + if (isMiuixEngine) { + MiuixCard( + cornerRadius = 16.dp, + insideMargin = PaddingValues(16.dp), + colors = MiuixCardDefaults.defaultColors( + color = MiuixTheme.colorScheme.primaryVariant, + contentColor = MiuixTheme.colorScheme.onPrimary + ) + ) { + MiuixText("Miuix 目前为测试主题,且不对基于View的界面生效!") + } + } + + SplicedColumnGroup(title = stringResource(R.string.theme)) { if (isMiuixEngine) { DropdownListSettingItem( @@ -253,7 +274,9 @@ fun ThemeConfigScreen( selectedValue = ThemeConfig.composeEngine, displayEntries = stringArrayResource(R.array.composeEngine), entryValues = stringArrayResource(R.array.composeEngine_value), - onValueChange = { ThemeConfig.composeEngine = it } + onValueChange = { + ThemeConfig.composeEngine = it + } ) SliderSettingItem( title = stringResource(R.string.font_scale), @@ -531,47 +554,46 @@ fun ThemeConfigScreen( manageKey?.let { isDark -> BackgroundImageManageSheet( + show = true, isDarkTheme = isDark, onDismissRequest = { manageKey = null } ) } - if (showColorPicker) { - ColorPickerSheet( - initialColor = primaryColorValue.value, - onDismissRequest = { showColorPicker = false }, - onColorSelected = { color -> - primaryColorValue.value = color - ThemeConfig.cPrimary = color - ThemeStore.editTheme(context) - .primaryColor(color) - .apply() - DynamicColors.applyToActivitiesIfAvailable( - context.applicationContext as android.app.Application, - DynamicColorsOptions.Builder() - .setContentBasedSource(context.primaryColor) - .build() - ) - } - ) - } - if (showLauncherIconPicker) { - LauncherIconPickerSheet( - selectedValue = ThemeConfig.launcherIcon, - onDismissRequest = { showLauncherIconPicker = false }, - onValueChange = { - ThemeConfig.launcherIcon = it - LauncherIconHelp.changeIcon(it) - } - ) - } + ColorPickerSheet( + show = showColorPicker, + initialColor = primaryColorValue.value, + onDismissRequest = { showColorPicker = false }, + onColorSelected = { color -> + primaryColorValue.value = color + ThemeConfig.cPrimary = color + ThemeStore.editTheme(context) + .primaryColor(color) + .apply() + DynamicColors.applyToActivitiesIfAvailable( + context.applicationContext as android.app.Application, + DynamicColorsOptions.Builder() + .setContentBasedSource(context.primaryColor) + .build() + ) + } + ) - if (showThemeListDialog) { - ThemeListDialog( - onDismissRequest = { showThemeListDialog = false } - ) - } + LauncherIconPickerSheet( + show = showLauncherIconPicker, + selectedValue = ThemeConfig.launcherIcon, + onDismissRequest = { showLauncherIconPicker = false }, + onValueChange = { + ThemeConfig.launcherIcon = it + LauncherIconHelp.changeIcon(it) + } + ) + + ThemeListDialog( + show = showThemeListDialog, + onDismissRequest = { showThemeListDialog = false } + ) saveThemeKey?.let { key -> AlertDialog( @@ -652,7 +674,7 @@ fun ThemeModeSelector( Spacer(Modifier.size(ToggleButtonDefaults.IconSpacing)) - AppText(text = label) + Text(text = label) } } } diff --git a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt index 13594b5d6..771065d75 100644 --- a/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt +++ b/app/src/main/java/io/legado/app/ui/config/themeConfig/ThemeListDialog.kt @@ -38,7 +38,7 @@ import io.legado.app.help.config.OldThemeConfig import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.card.GlassCard -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.GSON import io.legado.app.utils.getClipText @@ -48,6 +48,7 @@ import io.legado.app.utils.toastOnUi @OptIn(ExperimentalMaterial3Api::class) @Composable fun ThemeListDialog( + show: Boolean, onDismissRequest: () -> Unit ) { val context = LocalContext.current @@ -55,7 +56,8 @@ fun ThemeListDialog( var deleteIndex by remember { mutableStateOf(null) } val themeList = remember(listVersion) { OldThemeConfig.configList.toList() } - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Column( diff --git a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt index 5d9f98ced..08145220d 100644 --- a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleEditSheet.kt @@ -36,7 +36,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.data.entities.DictRule -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch @@ -56,7 +56,8 @@ fun DictRuleEditSheet( var showRule by remember(rule) { mutableStateOf(rule?.showRule ?: "") } var showMenu by remember { mutableStateOf(false) } - GlassModalBottomSheet( + AppModalBottomSheet( + show = true, onDismissRequest = onDismissRequest ) { Box( diff --git a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt index e157fd51d..b67c34077 100644 --- a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt +++ b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt @@ -5,7 +5,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -44,13 +43,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.legado.app.R import io.legado.app.base.BaseRuleEvent import io.legado.app.data.entities.DictRule -import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.ActionItem import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.button.SmallIconButton import io.legado.app.ui.widget.components.card.ReorderableSelectionItem import io.legado.app.ui.widget.components.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.importComponents.BaseImportUiState import io.legado.app.ui.widget.components.importComponents.BatchImportDialog import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn @@ -153,54 +150,49 @@ fun DictRuleScreen( ) } - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - title = stringResource(R.string.export), - onSelectSysDir = { - showExportSheet = false - exportDoc.launch("exportDictRule.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + title = stringResource(R.string.export), + onSelectSysDir = { + showExportSheet = false + exportDoc.launch("exportDictRule.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_dict_rule), - onSelectSysFile = { types -> - importDoc.launch(types) - showImportSheet = false - }, - onManualInput = { - showUrlInput = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = "导入词典规则", - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - itemContent = { rule, _ -> - Column { - AppText(rule.name, style = LegadoTheme.typography.titleMedium) - AppText(rule.urlRule, style = LegadoTheme.typography.bodySmall, maxLines = 1) - } - } - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_dict_rule), + onSelectSysFile = { types -> + importDoc.launch(types) + showImportSheet = false + }, + onManualInput = { + showUrlInput = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) + + BatchImportDialog( + title = "导入词典规则", + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + itemTitle = { rule -> rule.name }, + itemSubtitle = { rule -> + rule.urlRule.takeIf { it.isNotBlank() } + } + ) LaunchedEffect(reorderableState.isAnyItemDragging) { if (!reorderableState.isAnyItemDragging) { @@ -228,47 +220,46 @@ fun DictRuleScreen( ) } - if (showEditSheet) { - RuleEditSheet( - rule = editingRule, - title = stringResource(R.string.dict_rule), - label1 = stringResource(R.string.url_rule), - label2 = stringResource(R.string.show_rule), - onDismissRequest = { - showEditSheet = false - editingRule = null - }, - onSave = { updatedRule -> - if (editingRule == null) { - viewModel.insert(updatedRule) - } else { - viewModel.update(updatedRule) - } - showEditSheet = false - editingRule = null - }, - onCopy = { viewModel.copyRule(it) }, - onPaste = { viewModel.pasteRule() }, - toFields = { r -> - RuleEditFields( - name = r?.name ?: "", - rule1 = r?.urlRule ?: "", - rule2 = r?.showRule ?: "" - ) - }, - fromFields = { fields, old -> - old?.copy( - name = fields.name, - urlRule = fields.rule1, - showRule = fields.rule2 - ) ?: DictRule( - name = fields.name, - urlRule = fields.rule1, - showRule = fields.rule2 - ) + RuleEditSheet( + show = showEditSheet, + rule = editingRule, + title = stringResource(R.string.dict_rule), + label1 = stringResource(R.string.url_rule), + label2 = stringResource(R.string.show_rule), + onDismissRequest = { + showEditSheet = false + editingRule = null + }, + onSave = { updatedRule -> + if (editingRule == null) { + viewModel.insert(updatedRule) + } else { + viewModel.update(updatedRule) } - ) - } + showEditSheet = false + editingRule = null + }, + onCopy = { viewModel.copyRule(it) }, + onPaste = { viewModel.pasteRule() }, + toFields = { r -> + RuleEditFields( + name = r?.name ?: "", + rule1 = r?.urlRule ?: "", + rule2 = r?.showRule ?: "" + ) + }, + fromFields = { fields, old -> + old?.copy( + name = fields.name, + urlRule = fields.rule1, + showRule = fields.rule2 + ) ?: DictRule( + name = fields.name, + urlRule = fields.rule1, + showRule = fields.rule2 + ) + } + ) RuleListScaffold( title = "字典规则", @@ -310,7 +301,7 @@ fun DictRuleScreen( snackbarHostState = snackbarHostState, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_str)) }, + text = stringResource(R.string.import_str), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) diff --git a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt index 2465c7f1d..1b19e510e 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.material3.WideNavigationRail import androidx.compose.material3.WideNavigationRailItem import androidx.compose.material3.WideNavigationRailValue @@ -195,7 +196,7 @@ fun MainScreen( ) { dismiss -> bookshelfUiState.groups.forEachIndexed { groupIndex, group -> RoundDropdownMenuItem( - text = { AppText(group.groupName) }, + text = group.groupName, onClick = { coroutineScope.launch { if (pagerState.currentPage != index) { @@ -321,7 +322,7 @@ private fun NavigationIcon( val icon = if (selected) destination.m3SelectedIcon else destination.m3Icon Box(modifier = modifier) { if (destination == MainDestination.Bookshelf && upBooksCount > 0) { - BadgedBox(badge = { Badge { AppText(upBooksCount.toString()) } }) { + BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) { Icon(icon, contentDescription = null) } } else { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt index 10c5bc5cd..89ded6312 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfConfigSheet.kt @@ -31,38 +31,37 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig -import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.card.GlassCard +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem import io.legado.app.ui.widget.components.settingItem.CompactSliderSettingItem import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem -import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun BookshelfConfigSheet( + show: Boolean, onDismissRequest: () -> Unit ) { val configuration = LocalConfiguration.current val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet( + title = stringResource(R.string.bookshelf_layout), + show = show, + onDismissRequest = onDismissRequest + ) { + GlassCard() { + + } Column( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) .animateContentSize() - .padding(horizontal = 16.dp) .padding(bottom = 32.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - AppText( - text = stringResource(R.string.bookshelf_layout), - style = LegadoTheme.typography.titleLarge, - modifier = Modifier.padding(vertical = 16.dp) - ) - - // Group Style CompactDropdownSettingItem( title = stringResource(R.string.group_style), selectedValue = BookshelfConfig.bookGroupStyle.toString(), diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt index 76dcafcce..fcb17f4fa 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt @@ -40,12 +40,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Surface -import androidx.compose.material3.Tab -import io.legado.app.ui.widget.components.text.AppText import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults import androidx.compose.material3.pulltorefresh.pullToRefresh import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState @@ -60,13 +57,11 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import io.legado.app.R @@ -86,7 +81,8 @@ import io.legado.app.ui.widget.components.lazylist.FastScrollLazyVerticalGrid import io.legado.app.ui.widget.components.list.ListScaffold import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem -import io.legado.app.ui.widget.components.tabRow.AdaptiveTabRow +import io.legado.app.ui.widget.components.tabRow.AppTabRow +import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.readText import io.legado.app.utils.startActivity import io.legado.app.utils.toastOnUi @@ -237,37 +233,37 @@ fun BookshelfScreen( topBarActions = { }, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.add_remote_book)) }, + text = stringResource(R.string.add_remote_book), onClick = { context.startActivity(); dismiss() }, leadingIcon = { Icon(Icons.Default.Wifi, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.book_local)) }, + text = stringResource(R.string.book_local), onClick = { context.startActivity(); dismiss() }, leadingIcon = { Icon(Icons.Default.Save, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.update_toc)) }, + text = stringResource(R.string.update_toc), onClick = { viewModel.upToc(uiState.items); dismiss() }, leadingIcon = { Icon(Icons.Default.Refresh, null) } ) RoundDropdownMenuItem( - text = { AppText("布局设置") }, + text = "布局设置", onClick = { showConfigSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.GridView, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.group_manage)) }, + text = stringResource(R.string.group_manage), onClick = { showGroupManageSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.Edit, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.add_url)) }, + text = stringResource(R.string.add_url), onClick = { showAddUrlDialog = true; dismiss() }, leadingIcon = { Icon(Icons.Default.Link, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.bookshelf_management)) }, + text = stringResource(R.string.bookshelf_management), onClick = { val groupId = uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L @@ -279,7 +275,7 @@ fun BookshelfScreen( leadingIcon = { Icon(Icons.Default.Settings, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.cache_export)) }, + text = stringResource(R.string.cache_export), onClick = { val groupId = uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L @@ -291,7 +287,7 @@ fun BookshelfScreen( leadingIcon = { Icon(Icons.Default.Download, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.export_bookshelf)) }, + text = stringResource(R.string.export_bookshelf), onClick = { showExportSheet = true dismiss() @@ -299,12 +295,12 @@ fun BookshelfScreen( leadingIcon = { Icon(Icons.Default.ImportExport, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_bookshelf)) }, + text = stringResource(R.string.import_bookshelf), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.log)) }, + text = stringResource(R.string.log), onClick = { showLogSheet = true dismiss() @@ -326,7 +322,7 @@ fun BookshelfScreen( uiState.groups.map { it.groupName } } - AdaptiveTabRow( + AppTabRow( tabTitles = tabTitles, selectedTabIndex = selectedTabIndex, onTabSelected = { index -> @@ -349,7 +345,7 @@ fun BookshelfScreen( ) { dismiss -> uiState.groups.forEachIndexed { index, group -> RoundDropdownMenuItem( - text = { AppText(group.groupName) }, + text = group.groupName, onClick = { scope.launch { pagerState.animateScrollToPage(index) } dismiss() @@ -487,13 +483,15 @@ fun BookshelfScreen( } } - if (showConfigSheet) { - BookshelfConfigSheet(onDismissRequest = { showConfigSheet = false }) - } + BookshelfConfigSheet( + show = showConfigSheet, + onDismissRequest = { showConfigSheet = false } + ) - if (showGroupManageSheet) { - GroupManageSheet(onDismissRequest = { showGroupManageSheet = false }) - } + GroupManageSheet( + show = showGroupManageSheet, + onDismissRequest = { showGroupManageSheet = false } + ) if (showAddUrlDialog) { SourceInputDialog( @@ -506,40 +504,39 @@ fun BookshelfScreen( ) } - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_bookshelf), - onSelectSysFile = { types -> - importLauncher.launch(types) - showImportSheet = false - }, - onManualInput = { - showAddUrlDialog = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_bookshelf), + onSelectSysFile = { types -> + importLauncher.launch(types) + showImportSheet = false + }, + onManualInput = { + showAddUrlDialog = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - title = stringResource(R.string.export_bookshelf), - onSelectSysDir = { - showExportSheet = false - exportLauncher.launch("bookshelf.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadBookshelf(uiState.items) - } - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + title = stringResource(R.string.export_bookshelf), + onSelectSysDir = { + showExportSheet = false + exportLauncher.launch("bookshelf.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadBookshelf(uiState.items) + } + ) - if (showLogSheet) { - AppLogSheet(onDismissRequest = { showLogSheet = false }) - } + AppLogSheet( + show = showLogSheet, + onDismissRequest = { showLogSheet = false } + ) if (uiState.isLoading) { Dialog(onDismissRequest = {}) { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt index 7149b5f13..0049f1095 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt @@ -6,18 +6,13 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -26,7 +21,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -35,10 +29,9 @@ import io.legado.app.R import io.legado.app.data.entities.BookGroup import io.legado.app.ui.book.group.GroupEditContent import io.legado.app.ui.book.group.GroupViewModel -import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.widget.components.button.SmallIconButton import io.legado.app.ui.widget.components.card.ReorderableSelectionItem -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet -import io.legado.app.ui.widget.components.text.AppText +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.utils.move import org.koin.androidx.compose.koinViewModel import sh.calvin.reorderable.rememberReorderableLazyListState @@ -46,6 +39,7 @@ import sh.calvin.reorderable.rememberReorderableLazyListState @OptIn(ExperimentalMaterial3Api::class) @Composable fun GroupManageSheet( + show: Boolean, onDismissRequest: () -> Unit, viewModel: GroupViewModel = koinViewModel(), bookshelfViewModel: BookshelfViewModel = koinViewModel() @@ -78,7 +72,22 @@ fun GroupManageSheet( } } - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet( + show = show, + onDismissRequest = onDismissRequest, + title = if (!isEditing) stringResource(R.string.group_manage) else stringResource(R.string.group_edit), + endAction = { + if (!isEditing) { + SmallIconButton( + onClick = { + editingGroup = null + isEditing = true + }, + icon = Icons.Default.Add + ) + } + } + ) { AnimatedContent( targetState = isEditing, transitionSpec = { @@ -93,56 +102,28 @@ fun GroupManageSheet( viewModel = viewModel ) } else { - Column( - modifier = Modifier - .fillMaxWidth() + LazyColumn( + state = listState, + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp) ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(vertical = 8.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - AppText( - text = stringResource(R.string.group_manage), - style = LegadoTheme.typography.titleLarge + items(listData, key = { it.groupId }) { group -> + val manageNameInfo = remember(group) { group.getManageName(context) } + ReorderableSelectionItem( + state = reorderableState, + key = group.groupId, + title = group.groupName.ifBlank { manageNameInfo.suffix.orEmpty() }, + subtitle = if (group.groupName.isNotBlank()) manageNameInfo.suffix else null, + isEnabled = group.show, + containerColor = MaterialTheme.colorScheme.surface, + onEnabledChange = { isChecked -> + viewModel.upGroup(group.copy(show = isChecked)) + }, + onClickEdit = { + editingGroup = group + isEditing = true + } ) - IconButton(onClick = { - editingGroup = null - isEditing = true - }) { - Icon( - Icons.Default.Add, - contentDescription = stringResource(R.string.add) - ) - } - } - - LazyColumn( - state = listState, - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - items(listData, key = { it.groupId }) { group -> - val manageNameInfo = remember(group) { group.getManageName(context) } - ReorderableSelectionItem( - state = reorderableState, - key = group.groupId, - title = group.groupName.ifBlank { manageNameInfo.suffix.orEmpty() }, - subtitle = if (group.groupName.isNotBlank()) manageNameInfo.suffix else null, - isEnabled = group.show, - containerColor = MaterialTheme.colorScheme.surface, - onEnabledChange = { isChecked -> - viewModel.upGroup(group.copy(show = isChecked)) - }, - onClickEdit = { - editingGroup = group - isEditing = true - } - ) - } } } } diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt index 9be3376af..568183b80 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt @@ -153,13 +153,13 @@ fun ExploreScreen( dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Group) }, - text = { AppText(stringResource(R.string.all)) }, + text = stringResource(R.string.all), onClick = { viewModel.setGroup(""); dismiss() } ) uiState.groups.forEach { group -> RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) }, - text = { AppText(group) }, + text = group, onClick = { viewModel.setGroup(group); dismiss() } ) } @@ -416,29 +416,29 @@ fun ExploreSourceHeader( PillHeaderDivider(title = item.bookSourceName) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) }, - text = { AppText(stringResource(R.string.to_top)) }, + text = stringResource(R.string.to_top), onClick = { onTop(); showMenu = false } ) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Edit) }, - text = { AppText(stringResource(R.string.edit)) }, + text = stringResource(R.string.edit), onClick = { onEdit(); showMenu = false } ) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Search) }, - text = { AppText(stringResource(R.string.search)) }, + text = stringResource(R.string.search), onClick = { onSearch(); showMenu = false } ) if (item.hasLoginUrl) { RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) }, - text = { AppText(stringResource(R.string.login)) }, + text = stringResource(R.string.login), onClick = { onLogin(); showMenu = false } ) } RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Refresh) }, - text = { AppText(stringResource(R.string.refresh)) }, + text = stringResource(R.string.refresh), onClick = { onRefresh(); showMenu = false } ) RoundDropdownMenuItem( @@ -448,12 +448,8 @@ fun ExploreSourceHeader( tint = MaterialTheme.colorScheme.error ) }, - text = { - AppText( - stringResource(R.string.delete), - color = MaterialTheme.colorScheme.error - ) - }, + text = stringResource(R.string.delete), + color = LegadoTheme.colorScheme.error, onClick = { onDelete(); showMenu = false } ) } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt b/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt index f752583fa..d1a63d6d8 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt @@ -239,7 +239,7 @@ fun WebServiceSettingBlock( Row( modifier = Modifier .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp, bottom = 12.dp), + .padding(start = 16.dp, end = 16.dp, top = 12.dp, bottom = 12.dp), horizontalArrangement = Arrangement.End ) { SmallTextButton( diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt index 3a25954cf..fed5dab27 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssScreen.kt @@ -136,12 +136,12 @@ fun RssScreen( dismiss() }, leadingIcon = { MenuItemIcon(Icons.Default.Settings) }, - text = { AppText("订阅源管理") } + text = "订阅源管理" ) PillDivider() RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Group) }, - text = { AppText(stringResource(R.string.all)) }, + text = stringResource(R.string.all), onClick = { viewModel.setGroup("") dismiss() @@ -150,7 +150,7 @@ fun RssScreen( uiState.groups.forEach { group -> RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Outlined.Label) }, - text = { AppText(group) }, + text = group, onClick = { viewModel.setGroup(group) dismiss() @@ -247,7 +247,7 @@ fun RssSourceGridItem( PillHeaderDivider(title = source.sourceName) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.VerticalAlignTop) }, - text = { AppText(stringResource(R.string.to_top)) }, + text = stringResource(R.string.to_top), onClick = { onTop() showMenu = false @@ -255,7 +255,7 @@ fun RssSourceGridItem( ) RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Edit) }, - text = { AppText(stringResource(R.string.edit)) }, + text = stringResource(R.string.edit), onClick = { onEdit() showMenu = false @@ -264,7 +264,7 @@ fun RssSourceGridItem( if (!source.loginUrl.isNullOrBlank()) { RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.AutoMirrored.Filled.Login) }, - text = { AppText(stringResource(R.string.login)) }, + text = stringResource(R.string.login), onClick = { onLogin() showMenu = false @@ -273,7 +273,7 @@ fun RssSourceGridItem( } RoundDropdownMenuItem( leadingIcon = { MenuItemIcon(Icons.Default.Close) }, - text = { AppText(stringResource(R.string.disable_source)) }, + text = stringResource(R.string.disable_source), onClick = { onDisable() showMenu = false @@ -286,12 +286,8 @@ fun RssSourceGridItem( tint = MaterialTheme.colorScheme.error ) }, - text = { - AppText( - stringResource(R.string.delete), - color = MaterialTheme.colorScheme.error - ) - }, + text = stringResource(R.string.delete), + color = MaterialTheme.colorScheme.error, onClick = { onDelete() showMenu = false diff --git a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt index 3cb2cf8f2..a254da5b2 100644 --- a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt +++ b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleScreen.kt @@ -8,7 +8,6 @@ import androidx.compose.animation.SharedTransitionScope import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -19,7 +18,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.FileOpen import androidx.compose.material3.AlertDialog -import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FloatingActionButton @@ -57,7 +55,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.legado.app.R import io.legado.app.base.BaseRuleEvent import io.legado.app.data.entities.ReplaceRule -import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.ActionItem import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.GroupManageBottomSheet @@ -70,7 +67,7 @@ import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem import io.legado.app.ui.widget.components.rules.RuleListScaffold -import io.legado.app.ui.widget.components.tabRow.AdaptiveTabRow +import io.legado.app.ui.widget.components.tabRow.AppTabRow import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -161,56 +158,48 @@ fun ReplaceRuleScreen( ) } - if (showImportSheet) { - FilePickerSheet( - onDismissRequest = { showImportSheet = false }, - title = stringResource(R.string.import_replace_rule), - onSelectSysFile = { types -> - importDoc.launch(types) - showImportSheet = false - }, - onManualInput = { - showUrlInput = true - showImportSheet = false - }, - allowExtensions = arrayOf("json", "txt") - ) - } + FilePickerSheet( + show = showImportSheet, + onDismissRequest = { showImportSheet = false }, + title = stringResource(R.string.import_replace_rule), + onSelectSysFile = { types -> + importDoc.launch(types) + showImportSheet = false + }, + onManualInput = { + showUrlInput = true + showImportSheet = false + }, + allowExtensions = arrayOf("json", "txt") + ) - if (showExportSheet) { - FilePickerSheet( - onDismissRequest = { showExportSheet = false }, - onSelectSysDir = { - showExportSheet = false - exportDoc.launch("exportReplaceRule.json") - }, - onUpload = { - showExportSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } + FilePickerSheet( + show = showExportSheet, + onDismissRequest = { showExportSheet = false }, + onSelectSysDir = { + showExportSheet = false + exportDoc.launch("exportReplaceRule.json") + }, + onUpload = { + showExportSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = stringResource(R.string.import_replace_rule), - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - topBarActions = {}, - itemContent = { rule, _ -> - Column { - AppText(rule.name, style = LegadoTheme.typography.titleMedium) - if (!rule.group.isNullOrBlank()) { - AppText(rule.group!!, style = LegadoTheme.typography.bodySmall) - } - } - } - ) - } + BatchImportDialog( + title = stringResource(R.string.import_replace_rule), + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + topBarActions = {}, + itemTitle = { rule -> rule.name }, + itemSubtitle = { rule -> + rule.group?.takeIf { it.isNotBlank() } + } + ) if (importState is BaseImportUiState.Loading) { Dialog(onDismissRequest = { viewModel.cancelImport() }) { LoadingIndicator() } @@ -263,14 +252,15 @@ fun ReplaceRuleScreen( } } - if (showGroupManageSheet) { - GroupManageBottomSheet( - groups = groups, - onDismissRequest = { showGroupManageSheet = false }, - onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, - onDeleteGroup = { viewModel.delGroup(it) } - ) - } + + GroupManageBottomSheet( + show = showGroupManageSheet, + groups = groups, + onDismissRequest = { showGroupManageSheet = false }, + onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, + onDeleteGroup = { viewModel.delGroup(it) } + ) + showDeleteRuleDialog?.let { rule -> AlertDialog( @@ -343,7 +333,7 @@ fun ReplaceRuleScreen( }, bottomContent = { if (tabItems.size > 1) { - AdaptiveTabRow( + AppTabRow( tabTitles = tabItems, selectedTabIndex = selectedTabIndex, onTabSelected = { index -> @@ -384,29 +374,29 @@ fun ReplaceRuleScreen( snackbarHostState = snackbarHostState, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_str)) }, + text = stringResource(R.string.import_str), onClick = { showImportSheet = true; dismiss() }, leadingIcon = { Icon(Icons.Default.FileOpen, null) } ) RoundDropdownMenuItem( - text = { AppText("分组管理") }, + text = "分组管理", onClick = { showGroupManageSheet = true; dismiss() } ) RoundDropdownMenuItem( - text = { AppText("帮助") }, + text = "帮助", onClick = { /*TODO*/ dismiss() } ) PillDivider() RoundDropdownMenuItem( - text = { AppText("旧的在前") }, + text = "旧的在前", onClick = { viewModel.setSortMode("asc"); dismiss() } ) RoundDropdownMenuItem( - text = { AppText("新的在前") }, + text = "新的在前", onClick = { viewModel.setSortMode("desc"); dismiss() } ) RoundDropdownMenuItem( - text = { AppText("名称升序") }, + text = "名称升序", onClick = { viewModel.setSortMode("name_asc") dismiss() @@ -416,7 +406,7 @@ fun ReplaceRuleScreen( } ) RoundDropdownMenuItem( - text = { AppText("名称降序") }, + text = "名称降序", onClick = { viewModel.setSortMode("name_desc") dismiss() @@ -473,16 +463,16 @@ fun ReplaceRuleScreen( //clipInOverlayDuringTransition = OverlayClip(RoundedCornerShape(12.dp)) ), dropdownContent = { dismiss -> - DropdownMenuItem( - text = { AppText("移至顶部") }, + RoundDropdownMenuItem( + text = "移至顶部", onClick = { viewModel.toTop(ui.rule); dismiss() } ) - DropdownMenuItem( - text = { AppText("移至底部") }, + RoundDropdownMenuItem( + text = "移至底部", onClick = { viewModel.toBottom(ui.rule); dismiss() } ) - DropdownMenuItem( - text = { AppText("删除") }, + RoundDropdownMenuItem( + text = "删除", onClick = { showDeleteRuleDialog = ui.rule; dismiss() } ) } diff --git a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt index 3cc61f0e2..2cdc02946 100644 --- a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt +++ b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt @@ -3,11 +3,9 @@ package io.legado.app.ui.rss.favorites import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons @@ -44,7 +42,6 @@ import io.legado.app.ui.widget.components.dialog.TextListInputDialog import io.legado.app.ui.widget.components.divider.PillDivider import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem import io.legado.app.ui.widget.components.rules.RuleListScaffold -import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.startActivity @OptIn(ExperimentalMaterial3Api::class) @@ -129,11 +126,10 @@ fun RssFavoritesScreen( topBarActions = {}, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { + text = stringResource(R.string.all), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Default.Group, null, modifier = Modifier.size(18.dp)) - Spacer(Modifier.width(12.dp)) - AppText(stringResource(R.string.all)) } }, onClick = { @@ -143,15 +139,14 @@ fun RssFavoritesScreen( ) groups.forEach { group -> RoundDropdownMenuItem( - text = { + text = group, + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon( Icons.AutoMirrored.Outlined.Label, null, modifier = Modifier.size(18.dp) ) - Spacer(Modifier.width(12.dp)) - AppText(group) } }, onClick = { @@ -162,11 +157,10 @@ fun RssFavoritesScreen( } PillDivider() RoundDropdownMenuItem( - text = { + text = stringResource(R.string.delete_select_group), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Default.DeleteSweep, null, modifier = Modifier.size(18.dp)) - Spacer(Modifier.width(12.dp)) - AppText(stringResource(R.string.delete_select_group)) } }, onClick = { @@ -175,11 +169,10 @@ fun RssFavoritesScreen( } ) RoundDropdownMenuItem( - text = { + text = stringResource(R.string.all), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Default.DeleteForever, null, modifier = Modifier.size(18.dp)) - Spacer(Modifier.width(12.dp)) - AppText(stringResource(R.string.all)) } }, onClick = { @@ -248,14 +241,14 @@ fun RssFavoritesScreen( }, dropdownContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.change_group)) }, + text = stringResource(R.string.change_group), onClick = { showSetGroupDialog = rssStar dismiss() } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.delete)) }, + text = stringResource(R.string.delete), onClick = { viewModel.deleteStar(rssStar) dismiss() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt index ee194858c..513cf214b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt @@ -5,7 +5,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -41,7 +40,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.legado.app.R import io.legado.app.base.BaseRuleEvent import io.legado.app.data.entities.RssSource -import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.ActionItem import io.legado.app.ui.widget.components.DraggableSelectionHandler import io.legado.app.ui.widget.components.GroupManageBottomSheet @@ -50,7 +48,6 @@ import io.legado.app.ui.widget.components.card.ReorderableSelectionItem import io.legado.app.ui.widget.components.dialog.TextListInputDialog import io.legado.app.ui.widget.components.divider.PillDivider import io.legado.app.ui.widget.components.filePicker.FilePickerSheet -import io.legado.app.ui.widget.components.importComponents.BaseImportUiState import io.legado.app.ui.widget.components.importComponents.BatchImportDialog import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn @@ -175,50 +172,41 @@ fun RssSourceScreen( ) } - if (showGroupManageSheet) { - GroupManageBottomSheet( - groups = groups, - onDismissRequest = { showGroupManageSheet = false }, - onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, - onDeleteGroup = { viewModel.delGroup(it) } - ) - } + GroupManageBottomSheet( + show = showGroupManageSheet, + groups = groups, + onDismissRequest = { showGroupManageSheet = false }, + onUpdateGroup = { old, new -> viewModel.upGroup(old, new) }, + onDeleteGroup = { viewModel.delGroup(it) } + ) - if (showFilePickerSheet) { - FilePickerSheet( - onDismissRequest = { showFilePickerSheet = false }, - onSelectSysDir = { - showFilePickerSheet = false - exportDoc.launch("exportRssSource.json") - }, - onUpload = { - showFilePickerSheet = false - viewModel.uploadSelectedRules(selectedIds, rules) - }, - allowExtensions = arrayOf("json") - ) - } - (importState as? BaseImportUiState.Success)?.let { state -> - BatchImportDialog( - title = stringResource(R.string.import_rss_source), - importState = state, - onDismissRequest = { viewModel.cancelImport() }, - onToggleItem = { viewModel.toggleImportSelection(it) }, - onToggleAll = { viewModel.toggleImportAll(it) }, - onConfirm = { viewModel.saveImportedRules() }, - itemContent = { source, _ -> - Column { - AppText(source.sourceName, style = LegadoTheme.typography.titleMedium) - AppText( - source.sourceUrl, - style = LegadoTheme.typography.bodySmall, - maxLines = 1 - ) - } - } - ) - } + FilePickerSheet( + show = showFilePickerSheet, + onDismissRequest = { showFilePickerSheet = false }, + onSelectSysDir = { + showFilePickerSheet = false + exportDoc.launch("exportRssSource.json") + }, + onUpload = { + showFilePickerSheet = false + viewModel.uploadSelectedRules(selectedIds, rules) + }, + allowExtensions = arrayOf("json") + ) + + BatchImportDialog( + title = stringResource(R.string.import_rss_source), + importState = importState, + onDismissRequest = { viewModel.cancelImport() }, + onToggleItem = { viewModel.toggleImportSelection(it) }, + onToggleAll = { viewModel.toggleImportAll(it) }, + onConfirm = { viewModel.saveImportedRules() }, + itemTitle = { rule -> rule.sourceName }, + itemSubtitle = { rule -> + rule.sourceUrl.takeIf { it.isNotBlank() } + } + ) LaunchedEffect(reorderableState.isAnyItemDragging) { if (!reorderableState.isAnyItemDragging) { @@ -291,11 +279,11 @@ fun RssSourceScreen( dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( onClick = { showGroupManageSheet = true }, - text = { AppText("分组管理") }, + text = "分组管理", ) Box { RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_rss_source)) }, + text = stringResource(R.string.import_rss_source), onClick = { showImportMenu = true } ) RoundDropdownMenu( @@ -303,7 +291,7 @@ fun RssSourceScreen( onDismissRequest = { showImportMenu = false } ) { RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_on_line)) }, + text = stringResource(R.string.import_on_line), onClick = { showImportMenu = false dismiss() @@ -311,7 +299,7 @@ fun RssSourceScreen( } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_local)) }, + text = stringResource(R.string.import_local), onClick = { showImportMenu = false dismiss() @@ -319,7 +307,7 @@ fun RssSourceScreen( } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.import_default_rule)) }, + text = stringResource(R.string.import_default_rule), onClick = { showImportMenu = false dismiss() @@ -330,29 +318,29 @@ fun RssSourceScreen( } PillDivider() RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.all)) }, + text = stringResource(R.string.all), onClick = { dismiss(); viewModel.setGroupFilter(null) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.enabled)) }, + text = stringResource(R.string.enabled), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_ENABLED) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.disabled)) }, + text = stringResource(R.string.disabled), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_DISABLED) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.need_login)) }, + text = stringResource(R.string.need_login), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_LOGIN) } ) RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.no_group)) }, + text = stringResource(R.string.no_group), onClick = { dismiss(); viewModel.setGroupFilter(RssSourceViewModel.FILTER_NO_GROUP) } ) PillDivider() groups.forEach { group -> RoundDropdownMenuItem( - text = { AppText(group) }, + text = group, onClick = { dismiss(); viewModel.setGroupFilter("${RssSourceViewModel.PREFIX_GROUP}$group") } ) } diff --git a/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt b/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt index 0da339c1e..b3894acd9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt +++ b/app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubScreen.kt @@ -89,7 +89,8 @@ fun RuleSubScreen( topBarActions = {}, dropDownMenuContent = { dismiss -> RoundDropdownMenuItem( - text = { + text = stringResource(R.string.sort), + leadingIcon = { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.AutoMirrored.Filled.Sort, null, modifier = Modifier.size(18.dp)) Spacer(Modifier.size(12.dp)) @@ -185,7 +186,7 @@ fun RuleSubScreen( }, dropdownContent = { dismiss -> RoundDropdownMenuItem( - text = { AppText(stringResource(R.string.delete)) }, + text = stringResource(R.string.delete), onClick = { viewModel.delete(ruleSub) dismiss() diff --git a/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt b/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt index cac926249..88039c0ca 100644 --- a/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt +++ b/app/src/main/java/io/legado/app/ui/theme/AppTheme.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight import io.legado.app.ui.config.themeConfig.ThemeConfig import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.theme.ThemeController @@ -46,8 +47,15 @@ fun AppTheme( ) } - val themeColors = remember(colorScheme, darkTheme, seedColor, paletteStyle, colorSchemeMode) { - LegadoThemeColors( + val themeColors = remember( + colorScheme, + darkTheme, + seedColor, + paletteStyle, + colorSchemeMode, + composeEngine + ) { + LegadoThemeMode( colorScheme = colorScheme, isDark = darkTheme, seedColor = seedColor, @@ -61,45 +69,230 @@ fun AppTheme( CompositionLocalProvider( LocalLegadoThemeColors provides themeColors ) { - when { - ThemeResolver.isMiuixEngine(themeColors.composeEngine) -> { - val controller = remember(colorSchemeMode, darkTheme) { - ThemeController( - colorSchemeMode = colorSchemeMode, - isDark = darkTheme + if (ThemeResolver.isMiuixEngine(themeColors.composeEngine)) { + val controller = remember(colorSchemeMode, darkTheme) { + ThemeController(colorSchemeMode = colorSchemeMode, isDark = darkTheme) + } + + MiuixTheme(controller = controller) { + val miuixStyles = MiuixTheme.textStyles + val legadoTypography = remember(miuixStyles) { + LegadoTypography( + headlineLarge = miuixStyles.title1, + headlineLargeEmphasized = miuixStyles.title1.copy(fontWeight = FontWeight.Medium), + headlineMedium = miuixStyles.title2, + headlineMediumEmphasized = miuixStyles.title2.copy(fontWeight = FontWeight.Medium), + headlineSmall = miuixStyles.title3, + headlineSmallEmphasized = miuixStyles.title3.copy(fontWeight = FontWeight.Medium), + + + titleLarge = miuixStyles.headline1, + titleLargeEmphasized = miuixStyles.headline1.copy(fontWeight = FontWeight.Medium), + titleMedium = miuixStyles.headline2, + titleMediumEmphasized = miuixStyles.headline2.copy(fontWeight = FontWeight.Medium), + titleSmall = miuixStyles.subtitle, + titleSmallEmphasized = miuixStyles.subtitle.copy(fontWeight = FontWeight.Medium), + + + bodyLarge = miuixStyles.paragraph, + bodyLargeEmphasized = miuixStyles.paragraph.copy(fontWeight = FontWeight.Medium), + bodyMedium = miuixStyles.body1, + bodyMediumEmphasized = miuixStyles.body1.copy(fontWeight = FontWeight.Medium), + bodySmall = miuixStyles.body2, + bodySmallEmphasized = miuixStyles.body2.copy(fontWeight = FontWeight.Medium), + + labelLarge = miuixStyles.button, + labelLargeEmphasized = miuixStyles.button.copy(fontWeight = FontWeight.Medium), + labelMedium = miuixStyles.footnote1, + labelMediumEmphasized = miuixStyles.footnote1.copy(fontWeight = FontWeight.Medium), + labelSmall = miuixStyles.footnote2, + labelSmallEmphasized = miuixStyles.footnote2.copy(fontWeight = FontWeight.Medium) ) } - MiuixTheme( - controller = controller - ) { - val miuixTextStyles = MiuixTheme.textStyles - val mappedTypography = remember(miuixTextStyles) { - miuixStylesToM3Typography(miuixTextStyles) - } + val miuixColorScheme = MiuixTheme.colorScheme - CompositionLocalProvider( - LocalLegadoTypography provides mappedTypography - ) { - AppBackground(darkTheme = darkTheme) { - content() - } - } + val mappedColorScheme = remember(miuixColorScheme) { + LegadoColorScheme( + primary = miuixColorScheme.primary, + onPrimary = miuixColorScheme.onPrimary, + primaryContainer = miuixColorScheme.primaryContainer, + onPrimaryContainer = miuixColorScheme.onPrimaryContainer, + inversePrimary = miuixColorScheme.primaryVariant, + + secondary = miuixColorScheme.primary.copy(alpha = 0.5f), + onSecondary = miuixColorScheme.onPrimary.copy(alpha = 0.5f), + secondaryContainer = miuixColorScheme.primaryContainer.copy(alpha = 0.5f), + onSecondaryContainer = miuixColorScheme.onPrimaryContainer.copy(alpha = 0.5f), + + tertiary = miuixColorScheme.secondary, + onTertiary = miuixColorScheme.onSecondary, + tertiaryContainer = miuixColorScheme.secondaryContainer, + onTertiaryContainer = miuixColorScheme.onSecondaryContainer, + + // ================= 4. 背景与表面 (Background & Surface) ================= + background = miuixColorScheme.background, + onBackground = miuixColorScheme.onBackground, + + surface = miuixColorScheme.surface, + onSurface = miuixColorScheme.onSurface, + surfaceVariant = miuixColorScheme.surfaceVariant, + // M3 的 onSurfaceVariant 通常是次级文字色。Miuix 的 onSurfaceSecondary 完美契合这个语义 + onSurfaceVariant = miuixColorScheme.onSurfaceSecondary, + + // M3 中用于给 Surface 叠加一层极淡主题色的属性,通常直接取 primary + surfaceTint = miuixColorScheme.primary, + + // Inverse 系列通常用于深色模式下的反色提示(如 Snackbar)。 + // 简单映射法:直接用现有的 onSurface 和 surface 交叉互换。 + inverseSurface = miuixColorScheme.onSurface, + inverseOnSurface = miuixColorScheme.surface, + + // ================= 5. 错误状态 (Error) ================= + error = miuixColorScheme.error, + onError = miuixColorScheme.onError, + errorContainer = miuixColorScheme.errorContainer, + onErrorContainer = miuixColorScheme.onErrorContainer, + + // ================= 6. 边框、分割线与遮罩 (Outline & Scrim) ================= + outline = miuixColorScheme.outline, + // outlineVariant 在 M3 中常用于分割线。Miuix 刚好有 dividerLine + outlineVariant = miuixColorScheme.dividerLine, + // scrim 是 M3 的遮罩层(如弹窗背后的阴影)。Miuix 刚好有 windowDimming + scrim = miuixColorScheme.windowDimming, + + surfaceBright = miuixColorScheme.surface, // Miuix 缺省,用 surface 兜底 + surfaceDim = miuixColorScheme.background, // Miuix 缺省,用 background 兜底 + surfaceContainer = miuixColorScheme.surfaceContainer, + surfaceContainerHigh = miuixColorScheme.surfaceContainerHigh, + surfaceContainerHighest = miuixColorScheme.surfaceContainerHighest, + surfaceContainerLow = miuixColorScheme.secondaryContainer, + surfaceContainerLowest = miuixColorScheme.background, + + primaryFixed = miuixColorScheme.primaryContainer, + primaryFixedDim = miuixColorScheme.primary, + onPrimaryFixed = miuixColorScheme.onPrimaryContainer, + onPrimaryFixedVariant = miuixColorScheme.onPrimary, + secondaryFixed = miuixColorScheme.secondaryContainer, + secondaryFixedDim = miuixColorScheme.secondary, + onSecondaryFixed = miuixColorScheme.onSecondaryContainer, + onSecondaryFixedVariant = miuixColorScheme.onSecondary, + tertiaryFixed = miuixColorScheme.tertiaryContainer, + tertiaryFixedDim = miuixColorScheme.tertiaryContainerVariant, + onTertiaryFixed = miuixColorScheme.onTertiaryContainer, + onTertiaryFixedVariant = miuixColorScheme.onTertiaryContainer + ) + } + + CompositionLocalProvider( + LocalLegadoTypography provides legadoTypography, + LocalLegadoColorScheme provides mappedColorScheme + ) { + AppBackground(darkTheme = darkTheme) { content() } } } + } else { + val Typography = Typography() + MaterialExpressiveTheme( + colorScheme = colorScheme, + typography = Typography, + motionScheme = MotionScheme.expressive(), + shapes = Shapes() + ) { + val legadoTypography = remember(Typography) { + LegadoTypography( + headlineLarge = Typography.headlineLarge, + headlineLargeEmphasized = Typography.headlineLargeEmphasized, + headlineMedium = Typography.headlineMedium, + headlineMediumEmphasized = Typography.headlineMediumEmphasized, + headlineSmall = Typography.headlineSmall, + headlineSmallEmphasized = Typography.headlineSmallEmphasized, - else -> { - MaterialExpressiveTheme( - colorScheme = colorScheme, - typography = Typography(), - motionScheme = MotionScheme.expressive(), - shapes = Shapes() + + titleLarge = Typography.titleLarge, + titleLargeEmphasized = Typography.titleLargeEmphasized, + titleMedium = Typography.titleMedium, + titleMediumEmphasized = Typography.titleMediumEmphasized, + titleSmall = Typography.titleSmall, + titleSmallEmphasized = Typography.titleSmallEmphasized, + + + bodyLarge = Typography.bodyLarge, + bodyLargeEmphasized = Typography.bodyLargeEmphasized, + bodyMedium = Typography.bodyMedium, + bodyMediumEmphasized = Typography.bodyMediumEmphasized, + bodySmall = Typography.bodySmall, + bodySmallEmphasized = Typography.bodySmallEmphasized, + + labelLarge = Typography.labelLarge, + labelLargeEmphasized = Typography.labelLargeEmphasized, + labelMedium = Typography.labelMedium, + labelMediumEmphasized = Typography.labelMediumEmphasized, + labelSmall = Typography.labelSmall, + labelSmallEmphasized = Typography.labelSmallEmphasized + ) + } + + val semanticColors = remember(colorScheme) { + LegadoColorScheme( + primary = colorScheme.primary, + onPrimary = colorScheme.onPrimary, + primaryContainer = colorScheme.primaryContainer, + onPrimaryContainer = colorScheme.onPrimaryContainer, + inversePrimary = colorScheme.inversePrimary, + secondary = colorScheme.secondary, + onSecondary = colorScheme.onSecondary, + secondaryContainer = colorScheme.secondaryContainer, + onSecondaryContainer = colorScheme.onSecondaryContainer, + tertiary = colorScheme.tertiary, + onTertiary = colorScheme.onTertiary, + tertiaryContainer = colorScheme.tertiaryContainer, + onTertiaryContainer = colorScheme.onTertiaryContainer, + background = colorScheme.background, + onBackground = colorScheme.onBackground, + surface = colorScheme.surface, + onSurface = colorScheme.onSurface, + surfaceVariant = colorScheme.surfaceVariant, + onSurfaceVariant = colorScheme.onSurfaceVariant, + surfaceTint = colorScheme.surfaceTint, + inverseSurface = colorScheme.inverseSurface, + inverseOnSurface = colorScheme.inverseOnSurface, + error = colorScheme.error, + onError = colorScheme.onError, + errorContainer = colorScheme.errorContainer, + onErrorContainer = colorScheme.onErrorContainer, + outline = colorScheme.outline, + outlineVariant = colorScheme.outlineVariant, + scrim = colorScheme.scrim, + surfaceBright = colorScheme.surfaceBright, + surfaceDim = colorScheme.surfaceDim, + surfaceContainer = colorScheme.surfaceContainer, + surfaceContainerHigh = colorScheme.surfaceContainerHigh, + surfaceContainerHighest = colorScheme.surfaceContainerHighest, + surfaceContainerLow = colorScheme.surfaceContainerLow, + surfaceContainerLowest = colorScheme.surfaceContainerLowest, + primaryFixed = colorScheme.primaryFixed, + primaryFixedDim = colorScheme.primaryFixedDim, + onPrimaryFixed = colorScheme.onPrimaryFixed, + onPrimaryFixedVariant = colorScheme.onPrimaryFixedVariant, + secondaryFixed = colorScheme.secondaryFixed, + secondaryFixedDim = colorScheme.secondaryFixedDim, + onSecondaryFixed = colorScheme.onSecondaryFixed, + onSecondaryFixedVariant = colorScheme.onSecondaryFixedVariant, + tertiaryFixed = colorScheme.tertiaryFixed, + tertiaryFixedDim = colorScheme.tertiaryFixedDim, + onTertiaryFixed = colorScheme.onTertiaryFixed, + onTertiaryFixedVariant = colorScheme.onTertiaryFixedVariant + ) + } + + CompositionLocalProvider( + LocalLegadoTypography provides legadoTypography, + LocalLegadoColorScheme provides semanticColors ) { - AppBackground(darkTheme = darkTheme) { - content() - } + AppBackground(darkTheme = darkTheme) { content() } } } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt b/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt index 292c2d277..b8d91d055 100644 --- a/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt +++ b/app/src/main/java/io/legado/app/ui/theme/LegadoTheme.kt @@ -1,18 +1,18 @@ package io.legado.app.ui.theme import androidx.compose.material3.ColorScheme -import androidx.compose.material3.Typography import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle import com.materialkolor.PaletteStyle import dev.chrisbanes.haze.HazeState import top.yukonga.miuix.kmp.theme.ColorSchemeMode -data class LegadoThemeColors( +data class LegadoThemeMode( val colorScheme: ColorScheme, val isDark: Boolean, val seedColor: Color, @@ -22,30 +22,117 @@ data class LegadoThemeColors( val composeEngine: String, ) +data class LegadoColorScheme( + val primary: Color, + val onPrimary: Color, + val primaryContainer: Color, + val onPrimaryContainer: Color, + val inversePrimary: Color, + val secondary: Color, + val onSecondary: Color, + val secondaryContainer: Color, + val onSecondaryContainer: Color, + val tertiary: Color, + val onTertiary: Color, + val tertiaryContainer: Color, + val onTertiaryContainer: Color, + val background: Color, + val onBackground: Color, + val surface: Color, + val onSurface: Color, + val surfaceVariant: Color, + val onSurfaceVariant: Color, + val surfaceTint: Color, + val inverseSurface: Color, + val inverseOnSurface: Color, + val error: Color, + val onError: Color, + val errorContainer: Color, + val onErrorContainer: Color, + val outline: Color, + val outlineVariant: Color, + val scrim: Color, + val surfaceBright: Color, + val surfaceDim: Color, + val surfaceContainer: Color, + val surfaceContainerHigh: Color, + val surfaceContainerHighest: Color, + val surfaceContainerLow: Color, + val surfaceContainerLowest: Color, + val primaryFixed: Color, + val primaryFixedDim: Color, + val onPrimaryFixed: Color, + val onPrimaryFixedVariant: Color, + val secondaryFixed: Color, + val secondaryFixedDim: Color, + val onSecondaryFixed: Color, + val onSecondaryFixedVariant: Color, + val tertiaryFixed: Color, + val tertiaryFixedDim: Color, + val onTertiaryFixed: Color, + val onTertiaryFixedVariant: Color, +) + +data class LegadoTypography( + val headlineLarge: TextStyle, + val headlineLargeEmphasized: TextStyle, + val headlineMedium: TextStyle, + val headlineMediumEmphasized: TextStyle, + val headlineSmall: TextStyle, + val headlineSmallEmphasized: TextStyle, + + val titleLarge: TextStyle, + val titleLargeEmphasized: TextStyle, + val titleMedium: TextStyle, + val titleMediumEmphasized: TextStyle, + val titleSmall: TextStyle, + val titleSmallEmphasized: TextStyle, + + + val bodyLarge: TextStyle, + val bodyLargeEmphasized: TextStyle, + val bodyMedium: TextStyle, + val bodyMediumEmphasized: TextStyle, + val bodySmall: TextStyle, + val bodySmallEmphasized: TextStyle, + + val labelLarge: TextStyle, + val labelLargeEmphasized: TextStyle, + val labelMedium: TextStyle, + val labelMediumEmphasized: TextStyle, + val labelSmall: TextStyle, + val labelSmallEmphasized: TextStyle, + + ) + +val LocalLegadoColorScheme = staticCompositionLocalOf { + error("No ColorScheme provided") +} + +val LocalLegadoTypography = staticCompositionLocalOf { + error("No Typography provided") +} + val LocalLegadoThemeColors = staticCompositionLocalOf { - LegadoThemeColors( + LegadoThemeMode( colorScheme = lightColorScheme(), isDark = false, seedColor = Color.Unspecified, paletteStyle = PaletteStyle.TonalSpot, themeMode = ColorSchemeMode.System, useDynamicColor = true, - composeEngine = "m3" + composeEngine = "material" ) } -val LocalLegadoTypography = staticCompositionLocalOf { - Typography() -} - val LocalHazeState = compositionLocalOf { null } object LegadoTheme { - val colorScheme: ColorScheme + val colorScheme: LegadoColorScheme @Composable @ReadOnlyComposable - get() = LocalLegadoThemeColors.current.colorScheme + get() = LocalLegadoColorScheme.current val isDark: Boolean @Composable @@ -77,7 +164,7 @@ object LegadoTheme { @ReadOnlyComposable get() = LocalLegadoThemeColors.current.useDynamicColor - val typography: Typography + val typography: LegadoTypography @Composable @ReadOnlyComposable get() = LocalLegadoTypography.current diff --git a/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt b/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt index 0d3370e7a..4e2b0c773 100644 --- a/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt +++ b/app/src/main/java/io/legado/app/ui/theme/ThemeManager.kt @@ -66,7 +66,8 @@ object ThemeManager { } AppThemeMode.CUSTOM -> { - CustomColorScheme(context.primaryColor, style) + val colorSpec = ThemeResolver.resolveColorSpecFromMaterialVersion(materialVersion) + CustomColorScheme(context.primaryColor, style, colorSpec) .getColorScheme(darkTheme) } @@ -93,4 +94,4 @@ object ThemeManager { return scheme } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt b/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt index 226185e92..20ae7b087 100644 --- a/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt +++ b/app/src/main/java/io/legado/app/ui/theme/ThemeResolver.kt @@ -67,4 +67,12 @@ object ThemeResolver { } } + fun resolveColorSpecFromMaterialVersion(value: String?): ThemeColorSpec { + return when (value) { + "material3Expressive" -> ThemeColorSpec.SPEC_2025 + "material3" -> ThemeColorSpec.SPEC_2021 + else -> ThemeColorSpec.SPEC_2021 + } + } + } diff --git a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt b/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt index 70d3ec548..98e3879df 100644 --- a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt +++ b/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt @@ -8,8 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandMore -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -22,26 +20,26 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.widget.components.card.GlassCard import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun CollapsibleHeader( modifier: Modifier = Modifier, + showIcon: Boolean = true, isCollapsed: Boolean, onToggle: () -> Unit, title: String, subtitle: String? = null, titleContent: (@Composable ColumnScope.() -> Unit)? = null ) { - Card( + GlassCard( modifier = modifier .fillMaxWidth() .padding(start = 16.dp, top = 4.dp, end = 16.dp), shape = MaterialTheme.shapes.medium, - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surfaceContainer - ), + containerColor = LegadoTheme.colorScheme.surfaceContainer, onClick = onToggle ) { Row( @@ -59,7 +57,7 @@ fun CollapsibleHeader( text = title, style = LegadoTheme.typography.bodySmallEmphasized.copy( fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.primary + color = LegadoTheme.colorScheme.primary ), maxLines = 1, overflow = TextOverflow.Ellipsis @@ -68,7 +66,7 @@ fun CollapsibleHeader( AppText( text = it, style = LegadoTheme.typography.labelSmallEmphasized.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant + color = LegadoTheme.colorScheme.onSurfaceVariant ), maxLines = 1, overflow = TextOverflow.Ellipsis @@ -82,12 +80,14 @@ fun CollapsibleHeader( label = "arrowRotation" ) - Icon( - imageVector = Icons.Default.ExpandMore, - contentDescription = if (isCollapsed) "展开" else "折叠", - modifier = Modifier.rotate(rotation), - tint = MaterialTheme.colorScheme.primary - ) + if (showIcon) { + Icon( + imageVector = Icons.Default.ExpandMore, + contentDescription = if (isCollapsed) "展开" else "折叠", + modifier = Modifier.rotate(rotation), + tint = LegadoTheme.colorScheme.primary + ) + } } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt deleted file mode 100644 index 4c6d5b557..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/components/AppIcon.kt +++ /dev/null @@ -1,49 +0,0 @@ -package io.legado.app.ui.widget.components - - -import androidx.compose.material3.Icon -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import io.legado.app.ui.theme.LegadoTheme.composeEngine -import io.legado.app.ui.theme.ThemeResolver -import androidx.compose.material3.LocalContentColor as MaterialLocalContentColor -import top.yukonga.miuix.kmp.basic.Icon as MiuixIcon -import top.yukonga.miuix.kmp.theme.LocalContentColor as MiuixLocalContentColor - -@Composable -fun AppIcon( - imageVector: ImageVector, - contentDescription: String?, - modifier: Modifier = Modifier, - tint: Color = currentContentColor(), -) { - val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - - if (isMiuix) { - MiuixIcon( - imageVector = imageVector, - contentDescription = contentDescription, - modifier = modifier, - tint = tint - ) - } else { - Icon( - imageVector = imageVector, - contentDescription = contentDescription, - modifier = modifier, - tint = tint - ) - } -} - -@Composable -fun currentContentColor(): Color { - val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - return if (isMiuix) { - MiuixLocalContentColor.current - } else { - MaterialLocalContentColor.current - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt index eb9eda5f4..f22b6a59b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/AppNavigationBar.kt @@ -5,6 +5,7 @@ import androidx.compose.material3.BottomAppBarDefaults import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItemDefaults +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -12,7 +13,6 @@ import androidx.compose.ui.graphics.vector.ImageVector import io.legado.app.ui.config.themeConfig.ThemeConfig import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver -import io.legado.app.ui.widget.components.text.AppText import top.yukonga.miuix.kmp.basic.NavigationBarDisplayMode import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.basic.NavigationBar as MiuixNavigationBar @@ -85,7 +85,7 @@ fun RowScope.AppNavigationBarItem( icon = m3Icon, colors = NavigationBarItemDefaults.colors(indicatorColor = m3IndicatorColor), label = if (m3ShowLabel) { - { AppText(labelString) } + { Text(labelString) } } else null, alwaysShowLabel = m3AlwaysShowLabel ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt new file mode 100644 index 000000000..956c90b46 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt @@ -0,0 +1,127 @@ +package io.legado.app.ui.widget.components + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.input.InputTransformation +import androidx.compose.foundation.text.input.KeyboardActionHandler +import androidx.compose.foundation.text.input.OutputTransformation +import androidx.compose.foundation.text.input.TextFieldLineLimits +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldColors +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.TextFieldLabelPosition +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.takeOrElse +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Density +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import io.legado.app.ui.widget.components.text.AppText +import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.TextField as MiuixTextField + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AppTextField( + state: TextFieldState, + modifier: Modifier = Modifier, + enabled: Boolean = true, + readOnly: Boolean = false, + // 1. 核心思想:保留 AppText 的统一样式与颜色降级参数 + textStyle: TextStyle? = null, + textColor: Color = Color.Unspecified, + // 2. 将 Label 统一定义为 String 以兼容两套引擎 + label: String? = null, + // 3. 保留 M3 TextField 的所有其他参数 + labelPosition: TextFieldLabelPosition = TextFieldLabelPosition.Attached(), + placeholder: @Composable (() -> Unit)? = null, + leadingIcon: @Composable (() -> Unit)? = null, + trailingIcon: @Composable (() -> Unit)? = null, + prefix: @Composable (() -> Unit)? = null, + suffix: @Composable (() -> Unit)? = null, + supportingText: @Composable (() -> Unit)? = null, + isError: Boolean = false, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + lineLimits: TextFieldLineLimits = TextFieldLineLimits.Default, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + scrollState: ScrollState = rememberScrollState(), + shape: Shape = TextFieldDefaults.shape, + colors: TextFieldColors = TextFieldDefaults.colors(), + contentPadding: PaddingValues? = null, + interactionSource: MutableInteractionSource? = null, +) { + val baseStyle = textStyle ?: LegadoTheme.typography.bodyMedium + val defaultTextColor = LegadoTheme.colorScheme.onSurface + val finalTextColor = textColor.takeOrElse { + baseStyle.color.takeOrElse { defaultTextColor } + } + val mergedTextStyle = baseStyle.merge(color = finalTextColor) + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + if (isMiuix) { + MiuixTextField( + state = state, + modifier = modifier, + enabled = enabled, + readOnly = readOnly, + textStyle = MiuixTheme.textStyles.main, + label = label ?: "", + leadingIcon = leadingIcon, + trailingIcon = trailingIcon, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + lineLimits = lineLimits, + onTextLayout = onTextLayout, + scrollState = scrollState, + interactionSource = interactionSource + ) + } else { + val resolvedContentPadding = + contentPadding ?: if (label == null || labelPosition is TextFieldLabelPosition.Above) { + TextFieldDefaults.contentPaddingWithoutLabel() + } else { + TextFieldDefaults.contentPaddingWithLabel() + } + TextField( + state = state, + modifier = modifier, + enabled = enabled, + readOnly = readOnly, + textStyle = mergedTextStyle, + labelPosition = labelPosition, + label = label?.let { { AppText(it) } }, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIcon = trailingIcon, + prefix = prefix, + suffix = suffix, + supportingText = supportingText, + isError = isError, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + lineLimits = lineLimits, + onTextLayout = onTextLayout, + scrollState = scrollState, + shape = shape, + colors = colors, + contentPadding = resolvedContentPadding, + interactionSource = interactionSource + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt b/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt index 66df4fb29..2659e0ee2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/EmptyMessageView.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.widget.components.text.AnimatedTextLine @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable diff --git a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt index 8d91e4feb..81ba5e057 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt @@ -1,12 +1,10 @@ package io.legado.app.ui.widget.components import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.input.rememberTextFieldState @@ -25,47 +23,36 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import io.legado.app.R -import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.button.SmallTextButton -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.settingItem.SettingItem import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun GroupManageBottomSheet( + show: Boolean, groups: List, onDismissRequest: () -> Unit, onUpdateGroup: (oldGroup: String, newGroup: String) -> Unit, onDeleteGroup: (group: String) -> Unit ) { - GlassModalBottomSheet( - onDismissRequest = onDismissRequest + AppModalBottomSheet( + show = show, + onDismissRequest = onDismissRequest, + title = stringResource(R.string.group_manage), ) { - Column( - modifier = Modifier - .padding(horizontal = 16.dp) - .padding(bottom = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - AppText( - modifier = Modifier.padding(bottom = 16.dp), - text = stringResource(R.string.group_manage), - style = LegadoTheme.typography.titleMedium - ) - LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) { - items(groups, key = { it }) { group -> - GroupItem( - group = group, - onUpdateGroup = onUpdateGroup, - onDeleteGroup = onDeleteGroup - ) - } + LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) { + items(groups, key = { it }) { group -> + GroupItem( + group = group, + onUpdateGroup = onUpdateGroup, + onDeleteGroup = onDeleteGroup + ) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt b/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt index d62ac9726..7f2facbae 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt @@ -1,32 +1,14 @@ package io.legado.app.ui.widget.components -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.animateContentSize -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.scaleIn -import androidx.compose.animation.scaleOut -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.input.TextFieldLineLimits -import androidx.compose.foundation.text.input.clearText import androidx.compose.foundation.text.input.rememberTextFieldState -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Clear -import androidx.compose.material.icons.filled.Search -import androidx.compose.material.icons.filled.VerticalAlignTop -import androidx.compose.material3.DropdownMenu import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -37,14 +19,15 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import io.legado.app.ui.widget.components.button.SmallIconButton +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import io.legado.app.ui.widget.components.icon.AppIcon +import io.legado.app.ui.widget.components.icon.AppIcons import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -53,10 +36,10 @@ fun SearchBarSection( onQueryChange: (String) -> Unit, placeholder: String = "搜索...", leadingIcon: @Composable (() -> Unit)? = { - SmallIconButton( - icon = Icons.Default.Search, - contentDescription = null, - onClick = {}) + AppIcon( + imageVector = AppIcons.Search, + contentDescription = null + ) }, backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerLow, scrollState: LazyListState? = null, @@ -65,7 +48,6 @@ fun SearchBarSection( dropdownMenu: (@Composable (onDismiss: () -> Unit) -> Unit)? = null ) { var showMenu by remember { mutableStateOf(false) } - val textFieldState = rememberTextFieldState(initialText = query) LaunchedEffect(query) { @@ -91,79 +73,19 @@ fun SearchBarSection( } } - Surface( - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp, bottom = 4.dp), - shape = RoundedCornerShape(32.dp), - color = backgroundColor - ) { - TextField( + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + val searchTextField = @Composable { + AppTextField( state = textFieldState, modifier = Modifier .fillMaxWidth() - .heightIn(min = 48.dp) - .padding(horizontal = 4.dp), + .then( + if (isMiuix) Modifier.padding(horizontal = 16.dp, vertical = 8.dp) + else Modifier + ), placeholder = { AppText(placeholder) }, leadingIcon = leadingIcon, - trailingIcon = { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(end = 4.dp) - .animateContentSize() - ) { - - AnimatedVisibility( - visible = textFieldState.text.isNotEmpty(), - enter = fadeIn() + scaleIn(), - exit = fadeOut() + scaleOut() - ) { - SmallIconButton( - onClick = { textFieldState.clearText() }, - icon = Icons.Default.Clear, - contentDescription = "清空输入" - ) - } - - AnimatedVisibility( - visible = showScrollToTop, - enter = fadeIn() + scaleIn(), - exit = fadeOut() + scaleOut() - ) { - SmallIconButton( - onClick = { - scope.launch { - scrollState?.animateScrollToItem(0) - } - }, - icon = Icons.Default.VerticalAlignTop, - contentDescription = "回到顶部" - ) - } - - if (trailingIcon != null) { - Box { - IconButton( - onClick = { - if (dropdownMenu != null) showMenu = true - } - ) { - trailingIcon() - } - - if (dropdownMenu != null) { - DropdownMenu( - expanded = showMenu, - onDismissRequest = { showMenu = false } - ) { - dropdownMenu { showMenu = false } - } - } - } - } - } - }, lineLimits = TextFieldLineLimits.SingleLine, colors = TextFieldDefaults.colors( focusedContainerColor = Color.Transparent, @@ -171,13 +93,21 @@ fun SearchBarSection( disabledContainerColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, - ), - contentPadding = PaddingValues( - top = 4.dp, - bottom = 4.dp, - start = 12.dp, - end = 12.dp ) ) } + + if (isMiuix) { + searchTextField() + } else { + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, bottom = 4.dp), + shape = RoundedCornerShape(32.dp), + color = backgroundColor + ) { + searchTextField() + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt b/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt new file mode 100644 index 000000000..3f0ca7038 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt @@ -0,0 +1,52 @@ +package io.legado.app.ui.widget.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Remove +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.widget.components.button.SmallOutlinedIconButton +import io.legado.app.ui.widget.components.card.TextCard + +@Composable +fun ValueStepper( + value: Float, + displayValue: Float, + valueRange: ClosedFloatingPointRange, + onValueChange: (Float) -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + SmallOutlinedIconButton( + onClick = { + val newValue = (value.toInt() - 1).toFloat().coerceIn(valueRange) + onValueChange(newValue) + }, + icon = Icons.Default.Remove + ) + TextCard( + cornerRadius = 8.dp, + horizontalPadding = 8.dp, + verticalPadding = 4.dp, + text = displayValue.toInt().toString(), + backgroundColor = LegadoTheme.colorScheme.surfaceContainer, + contentColor = LegadoTheme.colorScheme.onSurface + ) + SmallOutlinedIconButton( + onClick = { + val newValue = (value.toInt() + 1).toFloat().coerceIn(valueRange) + onValueChange(newValue) + }, + icon = Icons.Default.Add + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt index 832f97f4a..d436c0ca8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkEditSheet.kt @@ -7,13 +7,10 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.padding import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -25,13 +22,15 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import io.legado.app.data.entities.Bookmark -import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.button.PrimaryButton +import io.legado.app.ui.widget.components.button.SecondaryButton +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun BookmarkEditSheet( + show: Boolean, bookmark: Bookmark, onDismiss: () -> Unit, onSave: (Bookmark) -> Unit, @@ -42,21 +41,16 @@ fun BookmarkEditSheet( var bookText by remember { mutableStateOf(bookmark.bookText) } var content by remember { mutableStateOf(bookmark.content) } - GlassModalBottomSheet( - onDismissRequest = onDismiss + AppModalBottomSheet( + show = show, + onDismissRequest = onDismiss, + title = bookmark.chapterName, ) { Column( modifier = Modifier .fillMaxWidth() - .padding(16.dp) .navigationBarsPadding() ) { - AppText( - text = bookmark.chapterName, - style = LegadoTheme.typography.titleMedium, - modifier = Modifier.padding(bottom = 16.dp) - ) - OutlinedTextField( value = bookText, onValueChange = { bookText = it }, @@ -82,15 +76,13 @@ fun BookmarkEditSheet( horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically ) { - OutlinedButton( + SecondaryButton( onClick = { showDeleteConfirmDialog = true }, - colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.error), - modifier = Modifier.weight(1f) - ) { - AppText("删除") - } + modifier = Modifier.weight(1f), + text = "删除" + ) - Button( + PrimaryButton( onClick = { val newBookmark = bookmark.apply { this.bookText = bookText @@ -98,10 +90,9 @@ fun BookmarkEditSheet( } onSave(newBookmark) }, - modifier = Modifier.weight(1f) - ) { - AppText("保存") - } + modifier = Modifier.weight(1f), + text = "保存" + ) } Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt index cab80e10f..470d44a1c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/bookmark/BookmarkItem.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -31,7 +30,7 @@ fun BookmarkItem( onLongClick: () -> Unit ) { val backgroundColor by animateColorAsState( - targetValue = if (isDur) MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.3f) + targetValue = if (isDur) LegadoTheme.colorScheme.secondaryContainer.copy(alpha = 0.3f) else Color.Transparent, label = "BgColor" ) @@ -53,7 +52,7 @@ fun BookmarkItem( AppText( text = bookmark.chapterName, style = LegadoTheme.typography.titleSmallEmphasized, - color = if (isDur) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary + color = if (isDur) LegadoTheme.colorScheme.primary else LegadoTheme.colorScheme.secondary ) if (bookmark.bookText.isNotEmpty()) { @@ -63,7 +62,7 @@ fun BookmarkItem( style = LegadoTheme.typography.bodyMedium, maxLines = 2, overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.onSurfaceVariant + color = LegadoTheme.colorScheme.onSurfaceVariant ) } @@ -72,7 +71,7 @@ fun BookmarkItem( AppText( text = bookmark.content, style = LegadoTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.primary + color = LegadoTheme.colorScheme.primary ) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/AppButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/AppButton.kt new file mode 100644 index 000000000..5595c43ff --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/AppButton.kt @@ -0,0 +1,74 @@ +package io.legado.app.ui.widget.components.button + +import androidx.compose.material3.Button +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import io.legado.app.ui.theme.LegadoTheme.composeEngine +import io.legado.app.ui.theme.ThemeResolver +import top.yukonga.miuix.kmp.basic.Button as MiuixButton +import top.yukonga.miuix.kmp.basic.ButtonDefaults as MiuixButtonDefaults +import top.yukonga.miuix.kmp.basic.Text as MiuixText + +@Composable +fun PrimaryButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + text: String +) { + if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + colors = MiuixButtonDefaults.buttonColorsPrimary() + ) { + MiuixText( + text = text + ) + } + } else { + Button( + onClick = onClick, + modifier = modifier, + enabled = enabled, + ) { + Text( + text = text, + ) + } + } +} + +@Composable +fun SecondaryButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + text: String +) { + if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + colors = MiuixButtonDefaults.buttonColors() + ) { + MiuixText( + text = text + ) + } + } else { + OutlinedButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + ) { + Text( + text = text + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/AppIconButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/AppIconButton.kt new file mode 100644 index 000000000..c14bceaa3 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/AppIconButton.kt @@ -0,0 +1,61 @@ +package io.legado.app.ui.widget.components.button + +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonColors +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.unit.Dp +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import top.yukonga.miuix.kmp.basic.IconButton as MiuixIconButton +import top.yukonga.miuix.kmp.basic.IconButtonDefaults as MiuixIconButtonDefaults + +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun AppIconButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + interactionSource: MutableInteractionSource? = null, + //M3 + colors: IconButtonColors = IconButtonDefaults.iconButtonColors(), + shape: Shape = IconButtonDefaults.standardShape, + // MIUIX + holdDownState: Boolean = false, + miuixBackgroundColor: Color = Color.Unspecified, + miuixCornerRadius: Dp? = null, + miuixMinHeight: Dp? = null, + miuixMinWidth: Dp? = null, + content: @Composable () -> Unit +) { + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + if (isMiuix) { + MiuixIconButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + holdDownState = holdDownState, + backgroundColor = miuixBackgroundColor, + cornerRadius = MiuixIconButtonDefaults.CornerRadius, + minHeight = MiuixIconButtonDefaults.MinHeight, + minWidth = MiuixIconButtonDefaults.MinWidth, + content = content + ) + } else { + IconButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + colors = colors, + interactionSource = interactionSource, + shape = shape, + content = content + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixButton.kt similarity index 92% rename from app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt rename to app/src/main/java/io/legado/app/ui/widget/components/button/MiuixButton.kt index 27093ad7e..3fa9c73dd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixBackButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/MiuixButton.kt @@ -7,21 +7,21 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import io.legado.app.R import top.yukonga.miuix.kmp.basic.Icon -import top.yukonga.miuix.kmp.basic.IconButton import top.yukonga.miuix.kmp.icon.MiuixIcons import top.yukonga.miuix.kmp.icon.extended.Back import top.yukonga.miuix.kmp.theme.LocalContentColor import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.IconButton as MiuixIconButton @Composable -fun MiuixButton( +fun MiuixIconButton( modifier: Modifier = Modifier, imageVector: ImageVector = MiuixIcons.Regular.Back, tint: Color = LocalContentColor.current, contentDescription: String? = stringResource(id = R.string.back), onClick: () -> Unit, ) { - IconButton( + MiuixIconButton( onClick = onClick, modifier = modifier ) { @@ -44,7 +44,7 @@ fun MiuixToggleButton( uncheckedTint: Color = LocalContentColor.current, contentDescription: String? = null, ) { - IconButton( + MiuixIconButton( onClick = { onCheckedChange(!checked) }, modifier = modifier ) { diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt index 6d1a51ad0..6bd6ffc96 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.widget.components.button import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -80,8 +82,24 @@ fun SmallIconButton( fun SmallOutlinedIconButton( onClick: () -> Unit, icon: ImageVector, + modifier: Modifier = Modifier, contentDescription: String? = null ) { + + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + if (isMiuix) { + MiuixIconButton( + onClick = onClick, + modifier = modifier.size(32.dp), + backgroundColor = LegadoTheme.colorScheme.surfaceContainer + ) { + MiuixIcon( + imageVector = icon, + contentDescription = contentDescription, + modifier = Modifier.size(18.dp) + ) + } + } else { CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { OutlinedIconButton( onClick = onClick, @@ -102,6 +120,7 @@ fun SmallOutlinedIconButton( ) } } + } } @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -109,27 +128,42 @@ fun SmallOutlinedIconButton( fun SmallTonalIconButton( onClick: () -> Unit, icon: ImageVector, + modifier: Modifier = Modifier, contentDescription: String? = null ) { - CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { - FilledTonalIconButton( + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) + + if (isMiuix) { + MiuixIconButton( onClick = onClick, - modifier = Modifier.size( - IconButtonDefaults.extraSmallContainerSize( - IconButtonDefaults.IconButtonWidthOption.Uniform - ) - ), - shapes = IconButtonDefaults.shapes(), - colors = IconButtonDefaults.filledTonalIconButtonColors() + modifier = modifier.size(32.dp), + backgroundColor = LegadoTheme.colorScheme.surfaceContainer ) { - Icon( + MiuixIcon( imageVector = icon, contentDescription = contentDescription, - modifier = Modifier.size( - IconButtonDefaults.extraSmallIconSize - ) + modifier = Modifier.size(18.dp) ) } + } else { + CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { + FilledTonalIconButton( + onClick = onClick, + modifier = modifier.size( + IconButtonDefaults.extraSmallContainerSize( + IconButtonDefaults.IconButtonWidthOption.Uniform + ) + ), + shapes = IconButtonDefaults.shapes(), + colors = IconButtonDefaults.filledTonalIconButtonColors() + ) { + Icon( + imageVector = icon, + contentDescription = contentDescription, + modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize) + ) + } + } } } @@ -142,35 +176,67 @@ fun SmallOutlinedIconToggleButton( modifier: Modifier = Modifier, contentDescription: String? = null ) { - val defaultShape = IconButtonDefaults.extraSmallRoundShape - val pressedShape = IconButtonDefaults.extraSmallPressedShape - val checkedShape = IconButtonDefaults.extraSmallSelectedRoundShape + val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - val toggleShapes = remember(defaultShape, checkedShape) { - IconToggleButtonShapes( - shape = defaultShape, - pressedShape = pressedShape, - checkedShape = checkedShape + if (isMiuix) { + + val containerColor by animateColorAsState( + targetValue = if (checked) LegadoTheme.colorScheme.primaryContainer else LegadoTheme.colorScheme.surfaceContainer, + animationSpec = tween(150), + label = "MiuixToggleContainerColor" ) - } - CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { - OutlinedIconToggleButton( - checked = checked, - onCheckedChange = onCheckedChange, - modifier = modifier.size( - IconButtonDefaults.extraSmallContainerSize( - IconButtonDefaults.IconButtonWidthOption.Uniform - ) - ), - shapes = toggleShapes + val iconTint by animateColorAsState( + targetValue = if (checked) LegadoTheme.colorScheme.onPrimaryContainer else LegadoTheme.colorScheme.onSurfaceVariant, + animationSpec = tween(150), + label = "MiuixToggleIconTint" + ) + + MiuixIconButton( + onClick = { onCheckedChange(!checked) }, + modifier = modifier + .size(32.dp), + backgroundColor = containerColor ) { - Icon( + MiuixIcon( imageVector = icon, contentDescription = contentDescription, - modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize), + tint = iconTint, + modifier = Modifier.size(18.dp) ) } + + } else { + val defaultShape = IconButtonDefaults.extraSmallRoundShape + val pressedShape = IconButtonDefaults.extraSmallPressedShape + val checkedShape = IconButtonDefaults.extraSmallSelectedRoundShape + + val toggleShapes = remember(defaultShape, checkedShape) { + IconToggleButtonShapes( + shape = defaultShape, + pressedShape = pressedShape, + checkedShape = checkedShape + ) + } + + CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { + OutlinedIconToggleButton( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier.size( + IconButtonDefaults.extraSmallContainerSize( + IconButtonDefaults.IconButtonWidthOption.Uniform + ) + ), + shapes = toggleShapes + ) { + Icon( + imageVector = icon, + contentDescription = contentDescription, + modifier = Modifier.size(IconButtonDefaults.extraSmallIconSize), + ) + } + } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt index 4dc24e991..9c3d49600 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt @@ -12,7 +12,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.LegadoTheme.composeEngine +import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.widget.components.text.AppText +import top.yukonga.miuix.kmp.basic.Button as MiuixButton +import top.yukonga.miuix.kmp.basic.ButtonDefaults as MiuixButtonDefaults +import top.yukonga.miuix.kmp.basic.Text as MiuixText @Composable fun SmallTextButton( @@ -21,21 +26,33 @@ fun SmallTextButton( modifier: Modifier = Modifier, onClick: () -> Unit ) { - TextButton( - onClick = onClick, - modifier = modifier, - contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), - shape = MaterialTheme.shapes.small - ) { - Icon( - imageVector = icon, - contentDescription = null, - modifier = Modifier.size(16.dp) - ) - Spacer(Modifier.width(4.dp)) - AppText( - text = text, - style = LegadoTheme.typography.labelMedium - ) + if (ThemeResolver.isMiuixEngine(composeEngine)) { + MiuixButton( + onClick = onClick, + modifier = modifier, + colors = MiuixButtonDefaults.buttonColors() + ) { + MiuixText( + text = text + ) + } + } else { + TextButton( + onClick = onClick, + modifier = modifier, + contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), + shape = MaterialTheme.shapes.small + ) { + Icon( + imageVector = icon, + contentDescription = null, + modifier = Modifier.size(16.dp) + ) + Spacer(Modifier.width(4.dp)) + AppText( + text = text, + style = LegadoTheme.typography.labelMedium + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt index f6251874d..22edae070 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/button/TopBarButton.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.unit.dp import io.legado.app.ui.config.themeConfig.ThemeConfig import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver +import io.legado.app.ui.widget.components.icon.AppIcons import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults import kotlinx.coroutines.delay @@ -107,12 +108,12 @@ fun TopBarButton( fun TopbarNavigationButton( onClick: () -> Unit, modifier: Modifier = Modifier, - imageVector: ImageVector = Icons.AutoMirrored.Filled.ArrowBack, + imageVector: ImageVector = AppIcons.Back, contentDescription: String? = "返回", style: TopBarButtonVariant = TopBarButtonVariant.Filled ) { if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) { - MiuixButton( + MiuixIconButton( onClick = onClick, imageVector = imageVector, contentDescription = contentDescription, @@ -138,7 +139,7 @@ fun TopBarActionButton( ) { val enableProgressive = ThemeConfig.enableProgressiveBlur if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) { - MiuixButton( + MiuixIconButton( onClick = onClick, imageVector = imageVector, contentDescription = contentDescription, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt index f8db95733..221416e7f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt @@ -86,7 +86,6 @@ fun SelectionItemCard( GlassCard( onClick = onToggleSelection, modifier = modifier - .padding(horizontal = 16.dp) .fillMaxWidth(), shape = MaterialTheme.shapes.medium, containerColor = animatedContainerColor, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt index c548ce905..1e0f55646 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -17,11 +16,8 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.theme.LegadoTheme.composeEngine -import io.legado.app.ui.theme.ThemeResolver -import io.legado.app.ui.widget.components.AnimatedTextLine -import io.legado.app.ui.widget.components.AppIcon -import top.yukonga.miuix.kmp.theme.MiuixTheme +import io.legado.app.ui.widget.components.icon.AppIcon +import io.legado.app.ui.widget.components.text.AnimatedTextLine @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -40,17 +36,8 @@ fun TextCard( spacing: Dp = 4.dp, textStyle: TextStyle = LegadoTheme.typography.labelSmallEmphasized ) { - val isMiuix = ThemeResolver.isMiuixEngine(composeEngine) - - val defaultBackground = if (isMiuix) - MiuixTheme.colorScheme.surfaceContainer - else - MaterialTheme.colorScheme.primaryContainer - - val defaultContent = if (isMiuix) - MiuixTheme.colorScheme.onSurface - else - MaterialTheme.colorScheme.primary + val defaultBackground = LegadoTheme.colorScheme.surfaceContainer + val defaultContent = LegadoTheme.colorScheme.onSurface val finalBackgroundColor = backgroundColor ?: defaultBackground val finalContentColor = contentColor ?: defaultContent diff --git a/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt b/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt index ec7f0be47..dc452a334 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/cover/BookshelfCover.kt @@ -7,17 +7,13 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Update import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.theme.LegadoTheme.composeEngine -import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.widget.components.card.TextCard -import top.yukonga.miuix.kmp.theme.MiuixTheme @Composable fun BookshelfCover( @@ -31,16 +27,6 @@ fun BookshelfCover( sourceOrigin: String? = null, onLoadFinish: (() -> Unit)? = null ) { - val backgroundColor = if (ThemeResolver.isMiuixEngine(composeEngine)) { - MiuixTheme.colorScheme.primaryContainer.copy(alpha = 0.2f) - } else { - MaterialTheme.colorScheme.secondaryContainer - } - val contentColor = if (ThemeResolver.isMiuixEngine(composeEngine)) { - MiuixTheme.colorScheme.primary - } else { - MaterialTheme.colorScheme.onSecondaryContainer - } Box(modifier = modifier) { BookCover( name = name, @@ -58,8 +44,6 @@ fun BookshelfCover( modifier = Modifier .align(Alignment.TopEnd) .padding(2.dp), - backgroundColor = backgroundColor, - contentColor = contentColor, cornerRadius = 4.dp, horizontalPadding = 4.dp, verticalPadding = 0.dp diff --git a/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt index 26390c39c..76bae95ae 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/dialog/ColorPickerSheet.kt @@ -41,12 +41,13 @@ import com.github.skydoves.colorpicker.compose.HsvColorPicker import com.github.skydoves.colorpicker.compose.rememberColorPickerController import io.legado.app.R import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText @OptIn(ExperimentalMaterial3Api::class) @Composable fun ColorPickerSheet( + show: Boolean, initialColor: Int, onDismissRequest: () -> Unit, onColorSelected: (Int) -> Unit @@ -80,7 +81,7 @@ fun ColorPickerSheet( ) } - GlassModalBottomSheet(onDismissRequest = onDismissRequest) { + AppModalBottomSheet(show = show, onDismissRequest = onDismissRequest) { Column( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt index f97428813..cd4cff794 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillDivider.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -14,26 +13,39 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import top.yukonga.miuix.kmp.theme.MiuixTheme @Composable fun PillDivider( modifier: Modifier = Modifier, thickness: Dp = 2.dp, widthFraction: Float = 0.2f, - color: Color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.6f) + color: Color = LegadoTheme.colorScheme.outlineVariant.copy(alpha = 0.6f) ) { - Box( - modifier = modifier - .fillMaxWidth() - .padding(vertical = 4.dp), - contentAlignment = Alignment.Center - ) { + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + if (isMiuix) { Box( modifier = Modifier - .fillMaxWidth(widthFraction) - .height(thickness) - .clip(CircleShape) - .background(color) + .fillMaxWidth() + .height(4.dp) + .background(MiuixTheme.colorScheme.secondaryContainer) ) + } else { + Box( + modifier = modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .fillMaxWidth(widthFraction) + .height(thickness) + .clip(CircleShape) + .background(color) + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt index e189ed31c..d1d81729d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/divider/PillHeaderDivider.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -24,8 +23,8 @@ fun PillHeaderDivider( title: String, modifier: Modifier = Modifier, dotSize: Dp = 2.dp, - dotColor: Color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.8f), - titleColor: Color = MaterialTheme.colorScheme.primary + dotColor: Color = LegadoTheme.colorScheme.outlineVariant.copy(alpha = 0.8f), + titleColor: Color = LegadoTheme.colorScheme.primary ) { Row( modifier = modifier diff --git a/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt index 0ed751d4d..bdd0c3b8a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/filePicker/FilePickerSheet.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.InsertDriveFile @@ -17,7 +16,6 @@ import androidx.compose.material.icons.filled.CloudUpload import androidx.compose.material.icons.filled.EditNote import androidx.compose.material.icons.filled.FolderOpen import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -28,7 +26,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.icon.AppIcon +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText enum class FilePickerSheetMode { @@ -38,6 +37,7 @@ enum class FilePickerSheetMode { @OptIn(ExperimentalMaterial3Api::class) @Composable fun FilePickerSheet( + show: Boolean, onDismissRequest: () -> Unit, title: String = stringResource(R.string.select_operation), onSelectSysDir: (() -> Unit)? = null, @@ -47,22 +47,17 @@ fun FilePickerSheet( onUpload: (() -> Unit)? = null, allowExtensions: Array? = null, ) { - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, + title = title, onDismissRequest = onDismissRequest, - containerColor = { it.surface } + containerColor = LegadoTheme.colorScheme.surface ) { Column( modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 8.dp), + .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { - AppText( - text = title, - style = LegadoTheme.typography.titleMedium, - modifier = Modifier.padding(bottom = 20.dp) - ) - FlowRow( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp), @@ -127,7 +122,7 @@ private fun RowScope.FilePickerOptionCard( .weight(1f) .height(100.dp), shape = MaterialTheme.shapes.medium, - color = MaterialTheme.colorScheme.surfaceContainerLow, + color = LegadoTheme.colorScheme.surfaceContainerLow, tonalElevation = 2.dp ) { Column( @@ -135,11 +130,11 @@ private fun RowScope.FilePickerOptionCard( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - Icon( + AppIcon( imageVector = icon, contentDescription = null, modifier = Modifier.size(32.dp), - tint = MaterialTheme.colorScheme.primary + tint = LegadoTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(8.dp)) AppText( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt new file mode 100644 index 000000000..f8c8361fd --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcon.kt @@ -0,0 +1,88 @@ +package io.legado.app.ui.widget.components.icon + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.paint +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.geometry.isUnspecified +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.takeOrElse +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp +import io.legado.app.ui.theme.LegadoTheme + +/** + * 1. 基础 AppIcon 实现 + */ +@Composable +fun AppIcon( + painter: Painter, + contentDescription: String?, + modifier: Modifier = Modifier, + tint: Color = Color.Unspecified, +) { + val defaultTintColor = LegadoTheme.colorScheme.onSurface + val finalTint = tint.takeOrElse { defaultTintColor } + + val colorFilter = remember(finalTint) { + if (finalTint == Color.Unspecified) null else ColorFilter.tint(finalTint) + } + + val semantics = if (contentDescription != null) { + Modifier.semantics { + this.contentDescription = contentDescription + this.role = Role.Image + } + } else { + Modifier + } + + Box( + modifier + .defaultIconSize(painter) + .paint(painter, colorFilter = colorFilter, contentScale = ContentScale.Fit) + .then(semantics) + ) +} + +@Composable +fun AppIcon( + imageVector: ImageVector?, + contentDescription: String?, + modifier: Modifier = Modifier, + tint: Color = Color.Unspecified, +) { + if (imageVector == null) return + + AppIcon( + painter = rememberVectorPainter(imageVector), + contentDescription = contentDescription, + modifier = modifier, + tint = tint, + ) +} + +/** + * 3. 辅助扩展函数:处理图标的默认尺寸 + * M3 和 MIUIX 内部都有 defaultSizeFor,如果 painter 没有固有尺寸,默认设为 24.dp + */ +private fun Modifier.defaultIconSize(painter: Painter): Modifier { + return this.then( + if (painter.intrinsicSize == Size.Unspecified || painter.intrinsicSize.isUnspecified) { + Modifier.size(24.dp) + } else { + Modifier + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt new file mode 100644 index 000000000..df274d7fd --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt @@ -0,0 +1,54 @@ +package io.legado.app.ui.widget.components.icon + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Clear +import androidx.compose.material.icons.filled.Replay +import androidx.compose.material.icons.filled.Search +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.vector.ImageVector +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import top.yukonga.miuix.kmp.icon.MiuixIcons +import top.yukonga.miuix.kmp.icon.basic.Search +import top.yukonga.miuix.kmp.icon.extended.Back +import top.yukonga.miuix.kmp.icon.extended.Close +import top.yukonga.miuix.kmp.icon.extended.Refresh + +/** + * 应用全局图标映射层 + */ +object AppIcons { + + private val isMiuix: Boolean + @Composable + get() = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + + val Search: ImageVector + @Composable + get() = if (isMiuix) { + MiuixIcons.Basic.Search + } else { + Icons.Default.Search + } + + val Close: ImageVector + @Composable + get() = if (isMiuix) { + MiuixIcons.Close + } else { + Icons.Default.Clear + } + + val Back: ImageVector + @Composable + get() = if (isMiuix) { + MiuixIcons.Back + } else { + Icons.AutoMirrored.Filled.ArrowBack + } + + val Replay: ImageVector + @Composable + get() = if (isMiuix) MiuixIcons.Refresh ?: Icons.Default.Replay else Icons.Default.Replay +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt b/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt index 2c72a0c8e..e62220280 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/importComponents/ImportComponents.kt @@ -1,10 +1,6 @@ package io.legado.app.ui.widget.components.importComponents import android.annotation.SuppressLint -import androidx.compose.animation.animateColorAsState -import androidx.compose.animation.animateContentSize -import androidx.compose.animation.core.FastOutSlowInEasing -import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -26,16 +22,10 @@ import androidx.compose.material.icons.filled.SelectAll import androidx.compose.material3.AlertDialog import androidx.compose.material3.AssistChip import androidx.compose.material3.Button -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField @@ -44,7 +34,6 @@ import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -59,9 +48,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import io.legado.app.R import io.legado.app.ui.theme.LegadoTheme -import io.legado.app.ui.widget.components.AnimatedText import io.legado.app.ui.widget.components.AppScaffold -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.button.SmallIconButton +import io.legado.app.ui.widget.components.card.SelectionItemCard +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet +import io.legado.app.ui.widget.components.text.AnimatedText import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch @@ -116,31 +107,42 @@ fun SourceInputDialog( ) } +//TODO: 动画 @SuppressLint("ConfigurationScreenWidthHeight") @OptIn(ExperimentalMaterial3Api::class) @Composable fun BatchImportDialog( title: String, - importState: BaseImportUiState.Success, + importState: BaseImportUiState, onDismissRequest: () -> Unit, - onConfirm: (List) -> Unit, // 返回选中的原始数据列表 + onConfirm: (List) -> Unit, onToggleItem: (index: Int) -> Unit, onToggleAll: (isSelected: Boolean) -> Unit, onItemInfoClick: (index: Int) -> Unit = {}, - // 插槽:允许调用方自定义顶部菜单 topBarActions: @Composable RowScope.() -> Unit = {}, - // 插槽:自定义每一行的显示内容 - itemContent: @Composable (data: T, status: ImportStatus) -> Unit + itemTitle: (data: T) -> String, + itemSubtitle: (data: T) -> String? = { null } ) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val show = importState is BaseImportUiState.Success + + var cachedState by remember { mutableStateOf?>(null) } + if (importState is BaseImportUiState.Success) { + cachedState = importState + } + + if (!show && cachedState == null) return + val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } - val selectedCount = importState.items.count { it.isSelected } - val totalCount = importState.items.size - GlassModalBottomSheet( + val currentState = cachedState!! + val selectedCount = currentState.items.count { it.isSelected } + val totalCount = currentState.items.size + + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest, - containerColor = { it.surfaceContainer } + containerColor = LegadoTheme.colorScheme.surfaceContainer ) { AppScaffold( modifier = Modifier @@ -171,44 +173,34 @@ fun BatchImportDialog( ImportBottomBar( selectedCount = selectedCount, totalCount = totalCount, - onToggleSelectAll = { isAll -> onToggleAll(isAll) }, + onToggleSelectAll = onToggleAll, onConfirm = { - scope.launch { sheetState.hide() }.invokeOnCompletion { - if (!sheetState.isVisible) { - val selectedData = - importState.items.filter { it.isSelected }.map { it.data } - onConfirm(selectedData) - } - } + val selectedData = + currentState.items.filter { it.isSelected }.map { it.data } + onConfirm(selectedData) }, - onCancel = { - scope.launch { sheetState.hide() }.invokeOnCompletion { - if (!sheetState.isVisible) { - onDismissRequest() - } - } - } + onCancel = onDismissRequest ) } ) { padding -> LazyColumn( - modifier = Modifier - .padding(padding), + modifier = Modifier.padding(padding), contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - itemsIndexed(importState.items, key = { _, item -> item.data.hashCode() }) { index, itemWrapper -> + itemsIndexed( + currentState.items, + key = { _, item -> item.data.hashCode() }) { index, itemWrapper -> ImportItemRow( + title = itemTitle(itemWrapper.data), + subtitle = itemSubtitle(itemWrapper.data), isSelected = itemWrapper.isSelected, status = itemWrapper.status, onClick = { onToggleItem(index) }, onInfoClick = { - scope.launch { - snackbarHostState.showSnackbar("其实还没写桀桀桀") - } + scope.launch { snackbarHostState.showSnackbar("其实还没写桀桀桀") } onItemInfoClick(index) - }, - content = { itemContent(itemWrapper.data, itemWrapper.status) } + } ) } } @@ -216,74 +208,47 @@ fun BatchImportDialog( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable -private fun ImportItemRow( +fun ImportItemRow( + title: String, + subtitle: String? = null, isSelected: Boolean, status: ImportStatus, onClick: () -> Unit, - onInfoClick: () -> Unit, - content: @Composable () -> Unit + onInfoClick: () -> Unit ) { - val containerColor by animateColorAsState( - targetValue = if (isSelected) - MaterialTheme.colorScheme.secondaryContainer - else - MaterialTheme.colorScheme.surface, - animationSpec = tween( - durationMillis = 200, - easing = FastOutSlowInEasing - ), - label = "CardColor" - ) - - Card( - onClick = onClick, - modifier = Modifier.fillMaxWidth(), - shape = MaterialTheme.shapes.medium, - colors = CardDefaults.cardColors( - containerColor = containerColor - ) - ) { - ListItem( - modifier = Modifier.animateContentSize(), - headlineContent = { content() }, - leadingContent = { - Checkbox( - checked = isSelected, - onCheckedChange = null - ) - }, - supportingContent = { - AppText( - text = when (status) { - ImportStatus.New -> "新增" - ImportStatus.Update -> "更新" - ImportStatus.Existing -> "已有" - ImportStatus.Error -> "错误" - }, - style = LegadoTheme.typography.labelMedium, - color = when (status) { - ImportStatus.New -> MaterialTheme.colorScheme.primary - ImportStatus.Update -> MaterialTheme.colorScheme.secondary - ImportStatus.Error -> MaterialTheme.colorScheme.error - else -> MaterialTheme.colorScheme.outline - } - ) - }, - trailingContent = { - IconButton(onClick = onInfoClick) { - Icon( - imageVector = Icons.Default.Info, - contentDescription = "详情" - ) - } - }, - colors = ListItemDefaults.colors( - containerColor = Color.Transparent + SelectionItemCard( + title = title, + subtitle = subtitle, + isSelected = isSelected, + inSelectionMode = true, + onToggleSelection = onClick, + modifier = Modifier.padding(vertical = 4.dp), + trailingAction = { + AppText( + text = when (status) { + ImportStatus.New -> "新增" + ImportStatus.Update -> "更新" + ImportStatus.Existing -> "已有" + ImportStatus.Error -> "错误" + }, + style = LegadoTheme.typography.labelMedium, + color = when (status) { + ImportStatus.New -> MaterialTheme.colorScheme.primary + ImportStatus.Update -> MaterialTheme.colorScheme.secondary + ImportStatus.Error -> MaterialTheme.colorScheme.error + else -> MaterialTheme.colorScheme.outline + }, + modifier = Modifier.padding(end = 4.dp) ) - ) - } + + SmallIconButton( + onClick = onInfoClick, + icon = Icons.Default.Info, + contentDescription = "详情" + ) + } + ) } @OptIn(ExperimentalMaterial3ExpressiveApi::class) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt b/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt index a9d75e7b3..c26987158 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/lazylist/VerticalFastScroller.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.util.fastFirstOrNull import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastLastOrNull import androidx.compose.ui.util.fastMaxBy +import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.lazylist.Scroller.STICKY_HEADER_KEY_PREFIX import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow @@ -67,7 +68,7 @@ fun VerticalFastScroller( listState: LazyListState, modifier: Modifier = Modifier, thumbAllowed: () -> Boolean = { true }, - thumbColor: Color = MaterialTheme.colorScheme.primary, + thumbColor: Color = LegadoTheme.colorScheme.primary, topContentPadding: Dp = Dp.Hairline, bottomContentPadding: Dp = Dp.Hairline, endContentPadding: Dp = Dp.Hairline, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt index 033191122..cbb74cc93 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt @@ -3,6 +3,8 @@ package io.legado.app.ui.widget.components.menuItem import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.material3.DropdownMenu import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialExpressiveTheme @@ -15,8 +17,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.theme.rememberOpaqueColorScheme - +import top.yukonga.miuix.kmp.basic.ListPopupColumn +import top.yukonga.miuix.kmp.extra.SuperListPopup @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable @@ -24,31 +29,50 @@ fun RoundDropdownMenu( expanded: Boolean, onDismissRequest: () -> Unit, modifier: Modifier = Modifier, + // M3 专属视觉参数,Miuix 模式下会优雅降级(忽略) shape: Shape = MaterialTheme.shapes.medium, shadowElevation: Dp = 4.dp, verticalSpacing: Dp = 8.dp, content: @Composable ColumnScope.(dismiss: () -> Unit) -> Unit ) { - val colorScheme = rememberOpaqueColorScheme() + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) - DropdownMenu( - expanded = expanded, - onDismissRequest = onDismissRequest, - modifier = modifier, - shape = shape, - shadowElevation = shadowElevation, - containerColor = colorScheme.surfaceContainerLow - ) { - MaterialExpressiveTheme( - colorScheme = colorScheme, - typography = Typography(), - motionScheme = MotionScheme.expressive(), - shapes = Shapes() + if (isMiuix) { + SuperListPopup( + show = expanded, + onDismissRequest = onDismissRequest, + popupModifier = modifier ) { - Column( - verticalArrangement = Arrangement.spacedBy(verticalSpacing) + ListPopupColumn { + Column() { + Spacer(Modifier.height(12.dp)) + content(onDismissRequest) + Spacer(Modifier.height(12.dp)) + } + } + } + } else { + val colorScheme = rememberOpaqueColorScheme() + + DropdownMenu( + expanded = expanded, + onDismissRequest = onDismissRequest, + modifier = modifier, + shape = shape, + shadowElevation = shadowElevation, + containerColor = colorScheme.surfaceContainerLow + ) { + MaterialExpressiveTheme( + colorScheme = colorScheme, + typography = Typography(), + motionScheme = MotionScheme.expressive(), + shapes = Shapes() ) { - content(onDismissRequest) + Column( + verticalArrangement = Arrangement.spacedBy(verticalSpacing) + ) { + content(onDismissRequest) + } } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt index 8e20a0531..437baaf81 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.widget.components.menuItem +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -11,54 +13,114 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn -import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.theme.rememberOpaqueColorScheme +import io.legado.app.ui.widget.components.icon.AppIcon +import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.Text as MiuixText @Composable fun RoundDropdownMenuItem( - text: @Composable () -> Unit, + text: String, + color: Color = LegadoTheme.colorScheme.surface, onClick: () -> Unit, modifier: Modifier = Modifier, + isSelected: Boolean = false, leadingIcon: @Composable (() -> Unit)? = null, trailingIcon: @Composable (() -> Unit)? = null, enabled: Boolean = true, contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding, interactionSource: MutableInteractionSource? = null, ) { - val colorScheme = rememberOpaqueColorScheme() + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) val interaction = interactionSource ?: remember { MutableInteractionSource() } - val contentColor = - if (enabled) MaterialTheme.colorScheme.onSurface - else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) + if (isMiuix) { + val backgroundColor = if (isSelected) { + LegadoTheme.colorScheme.primaryContainer + } else { + Color.Transparent + } - Surface( - onClick = onClick, - modifier = modifier - .padding(horizontal = 8.dp) - .fillMaxWidth(), - enabled = enabled, - shape = MaterialTheme.shapes.small, - color = colorScheme.surface, - interactionSource = interaction - ) { - CompositionLocalProvider( - LocalContentColor provides contentColor, - LocalTextStyle provides LegadoTheme.typography.labelLarge + val contentColor = if (isSelected) { + LegadoTheme.colorScheme.onPrimaryContainer + } else { + LegadoTheme.colorScheme.onSurface + } + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + modifier = modifier + .fillMaxWidth() + .drawBehind { drawRect(backgroundColor) } + .clickable( + interactionSource = interaction, + indication = androidx.compose.foundation.LocalIndication.current, + enabled = enabled, + onClick = onClick + ) + .padding(horizontal = 20.dp, vertical = 12.dp) + ) { + CompositionLocalProvider( + LocalContentColor provides contentColor, + LocalTextStyle provides MiuixTheme.textStyles.body1 + ) { + if (leadingIcon != null) { + leadingIcon() + Spacer(Modifier.width(12.dp)) + } + + Box( + modifier = Modifier.weight(1f), + contentAlignment = Alignment.CenterStart + ) { + MiuixText( + text = text, + fontWeight = FontWeight.Medium + ) + } + + if (trailingIcon != null) { + Spacer(Modifier.width(12.dp)) + trailingIcon() + } + } + } + } else { + val colorScheme = rememberOpaqueColorScheme() + val contentColor = if (enabled) { + MaterialTheme.colorScheme.onSurface + } else { + MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) + } + + Surface( + onClick = onClick, + modifier = modifier + .padding(horizontal = 8.dp) + .fillMaxWidth(), + enabled = enabled, + shape = MaterialTheme.shapes.small, + color = colorScheme.surface, + interactionSource = interaction ) { Row( modifier = Modifier @@ -67,17 +129,20 @@ fun RoundDropdownMenuItem( .widthIn(min = 120.dp), verticalAlignment = Alignment.CenterVertically ) { - if (leadingIcon != null) { leadingIcon() - Spacer(Modifier.width(8.dp)) + Spacer(Modifier.width(12.dp)) } Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.CenterStart ) { - text() + Text( + modifier = Modifier.widthIn(max = 200.dp), + text = text, + style = LegadoTheme.typography.bodyMediumEmphasized + ) } if (trailingIcon != null) { @@ -94,9 +159,9 @@ fun MenuItemIcon( imageVector: ImageVector, modifier: Modifier = Modifier, contentDescription: String? = null, - tint: Color = LocalContentColor.current + tint: Color = Color.Unspecified ) { - Icon( + AppIcon( imageVector = imageVector, contentDescription = contentDescription, modifier = modifier.size(18.dp), diff --git a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt new file mode 100644 index 000000000..b1b678f7e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt @@ -0,0 +1,138 @@ +package io.legado.app.ui.widget.components.modalBottomSheet + +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.BottomSheetDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MaterialExpressiveTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.MotionScheme +import androidx.compose.material3.Shapes +import androidx.compose.material3.Text +import androidx.compose.material3.Typography +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalWindowInfo +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.ThemeResolver +import io.legado.app.ui.theme.rememberOpaqueColorScheme +import top.yukonga.miuix.kmp.extra.WindowBottomSheet + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun AppModalBottomSheet( + show: Boolean, + onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, + title: String? = null, + startAction: @Composable (() -> Unit)? = null, + endAction: @Composable (() -> Unit)? = null, + containerColor: Color = LegadoTheme.colorScheme.surfaceContainerLow, + content: @Composable ColumnScope.() -> Unit +) { + if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) { + WindowBottomSheet( + show = show, + modifier = modifier, + title = title, + startAction = startAction, + endAction = endAction, + insideMargin = DpSize(16.dp, 12.dp), + backgroundColor = containerColor, + onDismissRequest = onDismissRequest, + onDismissFinished = onDismissRequest, + enableWindowDim = true, + allowDismiss = true + ) { + Column( + modifier = Modifier.fillMaxWidth(), + content = content + ) + } + } else { + if (show) { + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val colorScheme = rememberOpaqueColorScheme() + val density = LocalDensity.current + val maxHeight = with(density) { + LocalWindowInfo.current.containerSize.height.toDp() * 0.8f + } + + ModalBottomSheet( + onDismissRequest = onDismissRequest, + sheetState = sheetState, + containerColor = containerColor, + contentColor = colorScheme.onSurface, + dragHandle = { BottomSheetDefaults.DragHandle() } + ) { + MaterialExpressiveTheme( + colorScheme = colorScheme, + typography = Typography(), + motionScheme = MotionScheme.expressive(), + shapes = Shapes() + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .heightIn(max = maxHeight) + .animateContentSize() + .then(modifier) + ) { + val hasHeader = + !title.isNullOrEmpty() || startAction != null || endAction != null + + if (hasHeader) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp), + contentAlignment = Alignment.Center + ) { + if (startAction != null) { + Box(modifier = Modifier.align(Alignment.CenterStart)) { + startAction() + } + } + + if (!title.isNullOrEmpty()) { + Text( + text = title, + style = LegadoTheme.typography.titleMediumEmphasized, + color = colorScheme.onSurface, + textAlign = TextAlign.Center, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.padding(horizontal = 56.dp) + ) + } + + if (endAction != null) { + Box(modifier = Modifier.align(Alignment.CenterEnd)) { + endAction() + } + } + } + } + + content() + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/GlassModalBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/GlassModalBottomSheet.kt deleted file mode 100644 index 187cb8b30..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/GlassModalBottomSheet.kt +++ /dev/null @@ -1,64 +0,0 @@ -package io.legado.app.ui.widget.components.modalBottomSheet - -import androidx.compose.animation.animateContentSize -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn -import androidx.compose.material3.ColorScheme -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.MaterialExpressiveTheme -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.MotionScheme -import androidx.compose.material3.Shapes -import androidx.compose.material3.SheetState -import androidx.compose.material3.Typography -import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalWindowInfo -import io.legado.app.ui.theme.rememberOpaqueColorScheme - -@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) -@Composable -fun GlassModalBottomSheet( - onDismissRequest: () -> Unit, - modifier: Modifier = Modifier, - sheetState: SheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true - ), - containerColor: (ColorScheme) -> Color = { it.surfaceContainerLow }, - content: @Composable ColumnScope.() -> Unit -) { - val colorScheme = rememberOpaqueColorScheme() - val density = LocalDensity.current - val maxHeight = with(density) { - LocalWindowInfo.current.containerSize.height.toDp() * 0.8f - } - - ModalBottomSheet( - onDismissRequest = onDismissRequest, - sheetState = sheetState, - containerColor = containerColor(colorScheme), - contentColor = colorScheme.onSurface - ) { - MaterialExpressiveTheme( - colorScheme = colorScheme, - typography = Typography(), - motionScheme = MotionScheme.expressive(), - shapes = Shapes() - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .heightIn(max = maxHeight) - .animateContentSize() - .then(modifier), - content = content - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt index e2cb8063a..ae07cccf4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt @@ -35,7 +35,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import io.legado.app.R -import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet +import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.text.AppText import kotlinx.coroutines.launch @@ -52,6 +52,7 @@ data class RuleEditFields( @OptIn(ExperimentalMaterial3Api::class) @Composable fun RuleEditSheet( + show: Boolean, rule: T?, title: String, label1: String, @@ -74,7 +75,8 @@ fun RuleEditSheet( fun getCurrentEntity() = fromFields(RuleEditFields(name, rule1, rule2), rule) - GlassModalBottomSheet( + AppModalBottomSheet( + show = show, onDismissRequest = onDismissRequest ) { Box(modifier = Modifier.fillMaxWidth()) { diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt index e5e83b6f6..4934919f7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/CompactSettingItems.kt @@ -1,13 +1,12 @@ package io.legado.app.ui.widget.components.settingItem -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.filled.Remove import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -20,17 +19,22 @@ import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp -import io.legado.app.ui.widget.components.button.SmallOutlinedIconButton +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.LegadoTheme.composeEngine +import io.legado.app.ui.theme.ThemeResolver +import io.legado.app.ui.widget.components.ValueStepper import io.legado.app.ui.widget.components.card.TextCard import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem -import io.legado.app.ui.widget.components.text.AppText +import top.yukonga.miuix.kmp.basic.BasicComponent +import top.yukonga.miuix.kmp.extra.SuperSwitch +import top.yukonga.miuix.kmp.extra.WindowDropdown +import top.yukonga.miuix.kmp.basic.Slider as MiuixSlider @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable @@ -41,49 +45,73 @@ fun CompactDropdownSettingItem( entryValues: Array, description: String? = null, imageVector: ImageVector? = null, - color: Color? = MaterialTheme.colorScheme.surface, + color: Color? = LegadoTheme.colorScheme.surface, shape: Shape = MaterialTheme.shapes.small, onValueChange: (String) -> Unit ) { - val currentEntry = displayEntries.getOrNull(entryValues.indexOf(selectedValue)) ?: selectedValue + if (ThemeResolver.isMiuixEngine(composeEngine)) { + val selectedIndex = entryValues.indexOf(selectedValue).coerceAtLeast(0) + val spinnerItems = displayEntries.toList() - SettingItem( - title = title, - description = description, - imageVector = imageVector, - color = color, - shape = shape, - trailingContent = { - TextCard( - cornerRadius = 8.dp, - horizontalPadding = 8.dp, - verticalPadding = 4.dp, - text = currentEntry, - backgroundColor = MaterialTheme.colorScheme.surfaceContainer, - contentColor = MaterialTheme.colorScheme.onSurface - ) - }, - dropdownMenu = { onDismiss -> - displayEntries.forEachIndexed { index, display -> - RoundDropdownMenuItem( - text = { AppText(display) }, - onClick = { - onValueChange(entryValues[index]) - onDismiss() - }, - trailingIcon = if (selectedValue == entryValues[index]) { - { - Icon( - Icons.Default.Check, - contentDescription = null, - modifier = Modifier.size(18.dp) - ) - } - } else null - ) + WindowDropdown( + title = title, + summary = description, + items = spinnerItems, + selectedIndex = selectedIndex, + startAction = imageVector?.let { icon -> + { + Icon( + imageVector = icon, + contentDescription = null + ) + } + }, + onSelectedIndexChange = { index -> + onValueChange(entryValues[index]) } - } - ) + ) + } else { + val currentEntry = + displayEntries.getOrNull(entryValues.indexOf(selectedValue)) ?: selectedValue + + SettingItem( + title = title, + description = description, + imageVector = imageVector, + color = color, + shape = shape, + trailingContent = { + TextCard( + cornerRadius = 8.dp, + horizontalPadding = 8.dp, + verticalPadding = 4.dp, + text = currentEntry, + backgroundColor = MaterialTheme.colorScheme.surfaceContainer, + contentColor = MaterialTheme.colorScheme.onSurface + ) + }, + dropdownMenu = { onDismiss -> + displayEntries.forEachIndexed { index, display -> + RoundDropdownMenuItem( + text = display, + onClick = { + onValueChange(entryValues[index]) + onDismiss() + }, + trailingIcon = if (selectedValue == entryValues[index]) { + { + Icon( + Icons.Default.Check, + contentDescription = null, + modifier = Modifier.size(18.dp) + ) + } + } else null + ) + } + } + ) + } } @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -104,59 +132,78 @@ fun CompactSliderSettingItem( var sliderValue by remember(value) { mutableFloatStateOf(value) } var displayValue by remember(value) { mutableFloatStateOf(value) } - SettingItem( - title = title, - description = description, - imageVector = imageVector, - color = color, - shape = shape, - expanded = expanded, - onExpandChange = { expanded = it }, - trailingContent = { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - SmallOutlinedIconButton( - onClick = { - val newValue = (value.toInt() - 1).toFloat().coerceIn(valueRange) - onValueChange(newValue) - }, - icon = Icons.Default.Remove + if (ThemeResolver.isMiuixEngine(composeEngine)) { + Column(modifier = Modifier.fillMaxWidth()) { + BasicComponent( + title = title, + summary = description, + onClick = { expanded = !expanded }, + endActions = { + ValueStepper( + value = value, + displayValue = displayValue, + valueRange = valueRange, + onValueChange = onValueChange + ) + } + ) + + AnimatedVisibility(visible = expanded) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + MiuixSlider( + value = sliderValue, + onValueChange = { + sliderValue = it + displayValue = it + }, + onValueChangeFinished = { + onValueChange(sliderValue) + }, + valueRange = valueRange, + steps = steps, + modifier = Modifier.fillMaxWidth() + ) + } + } + } + } else { + SettingItem( + title = title, + description = description, + imageVector = imageVector, + color = color, + shape = shape, + expanded = expanded, + onExpandChange = { expanded = it }, + trailingContent = { + ValueStepper( + value = value, + displayValue = displayValue, + valueRange = valueRange, + onValueChange = onValueChange ) - TextCard( - cornerRadius = 8.dp, - horizontalPadding = 8.dp, - verticalPadding = 4.dp, - text = displayValue.toInt().toString(), - backgroundColor = MaterialTheme.colorScheme.surfaceContainer, - contentColor = MaterialTheme.colorScheme.onSurface - ) - SmallOutlinedIconButton( - onClick = { - val newValue = (value.toInt() + 1).toFloat().coerceIn(valueRange) - onValueChange(newValue) + }, + expandContent = { + Slider( + value = sliderValue, + onValueChange = { + sliderValue = it + displayValue = it }, - icon = Icons.Default.Add + onValueChangeFinished = { + onValueChange(sliderValue) + }, + valueRange = valueRange, + steps = steps, + modifier = Modifier.fillMaxWidth() ) } - }, - expandContent = { - Slider( - value = sliderValue, - onValueChange = { - sliderValue = it - displayValue = it - }, - onValueChangeFinished = { - onValueChange(sliderValue) - }, - valueRange = valueRange, - steps = steps, - modifier = Modifier.fillMaxWidth() - ) - } - ) + ) + } LaunchedEffect(value) { if (!expanded) { @@ -177,20 +224,30 @@ fun CompactSwitchSettingItem( enabled: Boolean = true, onCheckedChange: (Boolean) -> Unit ) { - SettingItem( - title = title, - description = description, - imageVector = imageVector, - color = color, - shape = shape, - onClick = { if (enabled) onCheckedChange(!checked) }, - trailingContent = { - Switch( - modifier = Modifier.scale(0.8f), - checked = checked, - onCheckedChange = onCheckedChange, - enabled = enabled - ) - } - ) + if (ThemeResolver.isMiuixEngine(composeEngine)) { + SuperSwitch( + title = title, + summary = description, + checked = checked, + onCheckedChange = onCheckedChange, + enabled = enabled, + ) + } else { + SettingItem( + title = title, + description = description, + imageVector = imageVector, + color = color, + shape = shape, + onClick = { if (enabled) onCheckedChange(!checked) }, + trailingContent = { + Switch( + modifier = Modifier.scale(0.8f), + checked = checked, + onCheckedChange = onCheckedChange, + enabled = enabled + ) + } + ) + } } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt index 532302557..f6db6cc20 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/ListSettingItem.kt @@ -11,7 +11,6 @@ import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem -import io.legado.app.ui.widget.components.text.AppText import top.yukonga.miuix.kmp.basic.SpinnerEntry import top.yukonga.miuix.kmp.extra.SuperSpinner @@ -64,7 +63,7 @@ fun DropdownListSettingItem( dropdownMenu = { onDismiss -> displayEntries.forEachIndexed { index, display -> RoundDropdownMenuItem( - text = { AppText(display) }, + text = display, onClick = { onValueChange(entryValues[index]) onDismiss() diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt index f0e458f20..e9263a254 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SwitchSettingItem.kt @@ -6,8 +6,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.widget.components.AdaptiveSwitch -import top.yukonga.miuix.kmp.basic.BasicComponent -import top.yukonga.miuix.kmp.basic.Switch +import top.yukonga.miuix.kmp.extra.SuperSwitch @Composable @@ -23,22 +22,12 @@ fun SwitchSettingItem( val composeEngine = LegadoTheme.composeEngine if (ThemeResolver.isMiuixEngine(composeEngine)) { - val toggleAction = { - if (enabled) onCheckedChange(!checked) - } - - BasicComponent( + SuperSwitch( title = title, summary = description, + checked = checked, + onCheckedChange = onCheckedChange, enabled = enabled, - onClick = toggleAction, - endActions = { - Switch( - checked = checked, - onCheckedChange = onCheckedChange, - enabled = enabled - ) - } ) } else { SettingItem( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt b/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AppTabRow.kt similarity index 95% rename from app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt rename to app/src/main/java/io/legado/app/ui/widget/components/tabRow/AppTabRow.kt index c9afdf567..a1cc3085d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AdaptiveTabRow.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/tabRow/AppTabRow.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.Tab +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -11,12 +12,11 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver -import io.legado.app.ui.widget.components.text.AppText import top.yukonga.miuix.kmp.basic.TabRowDefaults import top.yukonga.miuix.kmp.basic.TabRowWithContour @Composable -fun AdaptiveTabRow( +fun AppTabRow( tabTitles: List, selectedTabIndex: Int, onTabSelected: (Int) -> Unit, @@ -48,7 +48,7 @@ fun AdaptiveTabRow( selected = selectedTabIndex == index, onClick = { onTabSelected(index) }, text = { - AppText( + Text( text = title, maxLines = 1, overflow = TextOverflow.Ellipsis, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt b/app/src/main/java/io/legado/app/ui/widget/components/text/AnimatedText.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt rename to app/src/main/java/io/legado/app/ui/widget/components/text/AnimatedText.kt index cfa21f308..ac075d549 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/AnimatedText.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/text/AnimatedText.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.widget.components +package io.legado.app.ui.widget.components.text import androidx.compose.animation.AnimatedContent import androidx.compose.animation.fadeIn @@ -22,7 +22,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit -import io.legado.app.ui.widget.components.text.AppText @Composable fun AnimatedText( diff --git a/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt b/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt index 51a1735e5..0826f1579 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/text/AppText.kt @@ -1,11 +1,11 @@ package io.legado.app.ui.widget.components.text -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.Text +import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextStyle @@ -16,10 +16,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit -import io.legado.app.ui.theme.LegadoTheme.composeEngine -import io.legado.app.ui.theme.ThemeResolver -import top.yukonga.miuix.kmp.theme.MiuixTheme -import top.yukonga.miuix.kmp.basic.Text as MiuixText +import io.legado.app.ui.theme.LegadoTheme @Composable fun AppText( @@ -41,53 +38,41 @@ fun AppText( onTextLayout: ((TextLayoutResult) -> Unit)? = null, style: TextStyle? = null, ) { + val baseStyle = style ?: LegadoTheme.typography.bodyMedium - if (ThemeResolver.isMiuixEngine(composeEngine)) { - MiuixText( - text = text, - modifier = modifier, - color = color, - fontSize = fontSize, - fontStyle = fontStyle, - fontWeight = fontWeight, - fontFamily = fontFamily, - letterSpacing = letterSpacing, - textDecoration = textDecoration, - textAlign = textAlign, - lineHeight = lineHeight, - overflow = overflow, - softWrap = softWrap, - maxLines = maxLines, - minLines = minLines, - onTextLayout = onTextLayout, - style = style ?: MiuixTheme.textStyles.main - ) - } else { - Text( - text = text, - modifier = modifier, - color = color, - fontSize = fontSize, - fontStyle = fontStyle, - fontWeight = fontWeight, - fontFamily = fontFamily, - letterSpacing = letterSpacing, - textDecoration = textDecoration, - textAlign = textAlign, - lineHeight = lineHeight, - overflow = overflow, - softWrap = softWrap, - maxLines = maxLines, - minLines = minLines, - onTextLayout = onTextLayout ?: {}, - style = style ?: LocalTextStyle.current - ) + // 2. 获取默认文本色:直接拿你自己封装的 LegadoTheme.colorScheme.onSurface + val defaultTextColor = LegadoTheme.colorScheme.onSurface + + // 3. 颜色降级逻辑:传入的 color -> style 中的 color -> 主题默认色 + val finalTextColor = color.takeOrElse { + baseStyle.color.takeOrElse { defaultTextColor } } + + BasicText( + text = text, + modifier = modifier, + style = baseStyle.merge( + color = finalTextColor, + fontSize = fontSize, + fontWeight = fontWeight, + textAlign = textAlign ?: TextAlign.Unspecified, + lineHeight = lineHeight, + fontFamily = fontFamily, + textDecoration = textDecoration, + fontStyle = fontStyle, + letterSpacing = letterSpacing, + ), + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines + ) } @Composable fun AppText( - text: AnnotatedString, + text: AnnotatedString, // 接收 AnnotatedString modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, @@ -105,46 +90,36 @@ fun AppText( onTextLayout: ((TextLayoutResult) -> Unit)? = null, style: TextStyle? = null, ) { + // 1. 获取基础样式:如果外部没传 style,直接拿你自己封装的 LegadoTheme.typography.bodyMedium + // 这完美避开了 M3 的 LocalTextStyle,且自动适配 Miuix/M3 引擎! + val baseStyle = style ?: LegadoTheme.typography.bodyMedium - if (ThemeResolver.isMiuixEngine(composeEngine)) { - MiuixText( - text = text, - modifier = modifier, - color = color, - fontSize = fontSize, - fontStyle = fontStyle, - fontWeight = fontWeight, - fontFamily = fontFamily, - letterSpacing = letterSpacing, - textDecoration = textDecoration, - textAlign = textAlign, - lineHeight = lineHeight, - overflow = overflow, - softWrap = softWrap, - maxLines = maxLines, - minLines = minLines, - onTextLayout = onTextLayout ?: {}, - style = style ?: MiuixTheme.textStyles.main - ) - } else { - Text( - text = text, - modifier = modifier, - color = color, - fontSize = fontSize, - fontStyle = fontStyle, - fontWeight = fontWeight, - fontFamily = fontFamily, - letterSpacing = letterSpacing, - textDecoration = textDecoration, - textAlign = textAlign, - lineHeight = lineHeight, - overflow = overflow, - softWrap = softWrap, - maxLines = maxLines, - minLines = minLines, - onTextLayout = onTextLayout ?: {}, - style = style ?: LocalTextStyle.current - ) + // 2. 获取默认文本色:直接拿你自己封装的 LegadoTheme.colorScheme.onSurface + val defaultTextColor = LegadoTheme.colorScheme.onSurface + + // 3. 颜色降级逻辑:传入的 color -> style 中的 color -> 主题默认色 + val finalTextColor = color.takeOrElse { + baseStyle.color.takeOrElse { defaultTextColor } } + + BasicText( + text = text, + modifier = modifier, + style = baseStyle.merge( + color = finalTextColor, + fontSize = fontSize, + fontWeight = fontWeight, + textAlign = textAlign ?: TextAlign.Unspecified, + lineHeight = lineHeight, + fontFamily = fontFamily, + textDecoration = textDecoration, + fontStyle = fontStyle, + letterSpacing = letterSpacing, + ), + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines + ) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt index b88003858..9cbd6c4fc 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/DynamicTopAppBar.kt @@ -10,12 +10,9 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -23,12 +20,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import io.legado.app.ui.widget.components.AnimatedTextLine import io.legado.app.ui.widget.components.SearchBarSection import io.legado.app.ui.widget.components.button.TopBarActionButton import io.legado.app.ui.widget.components.button.TopbarNavigationButton +import io.legado.app.ui.widget.components.icon.AppIcons import io.legado.app.ui.widget.components.list.ListUiState import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu +import io.legado.app.ui.widget.components.text.AnimatedTextLine @OptIn(ExperimentalMaterial3Api::class) @@ -70,7 +68,7 @@ fun DynamicTopAppBar( if (isSelecting || onBackClick != null) { TopbarNavigationButton( onClick = { if (isSelecting) onClearSelection() else onBackClick?.invoke() }, - imageVector = if (isSelecting) Icons.Default.Close else Icons.AutoMirrored.Filled.ArrowBack, + imageVector = if (isSelecting) AppIcons.Close else AppIcons.Back, contentDescription = if (isSelecting) "取消选择" else "返回" ) } @@ -113,7 +111,6 @@ fun DynamicTopAppBar( query = state.searchKey, onQueryChange = onSearchQueryChange, placeholder = searchPlaceholder, - leadingIcon = { Icon(searchLeadingIcon, null) }, trailingIcon = searchTrailingIcon, dropdownMenu = searchDropdownMenu ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt index 0a1cee57e..118d14a5c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/topbar/GlassMediumFlexibleTopAppBar.kt @@ -21,8 +21,8 @@ import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.LocalHazeState import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.theme.responsiveHazeEffect -import io.legado.app.ui.widget.components.AdaptiveAnimatedText import io.legado.app.ui.widget.components.GlassDefaults +import io.legado.app.ui.widget.components.text.AdaptiveAnimatedText import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.basic.TopAppBar as MiuixTopAppBar