From 15f6efc42d1a2ebcca65aecb442db4736db51c59 Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Sun, 19 Apr 2026 02:34:40 +0800 Subject: [PATCH] =?UTF-8?q?[=E4=BC=98=E5=8C=96]=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/data/dao/ReadRecordDao.kt | 6 + .../data/repository/ReadRecordRepository.kt | 22 ++ .../app/ui/book/bookmark/AllBookmarkScreen.kt | 6 +- .../app/ui/book/explore/ExploreShowScreen.kt | 18 +- .../ui/book/import/remote/RemoteBookScreen.kt | 2 +- .../ui/book/readRecord/ReadRecordScreen.kt | 15 +- .../legado/app/ui/book/search/SearchScreen.kt | 344 +++++++++--------- .../book/searchContent/SearchContentScreen.kt | 4 +- .../io/legado/app/ui/book/toc/TocScreen.kt | 7 +- .../ui/config/coverConfig/CoverManageSheet.kt | 15 +- .../themeConfig/BackgroundImageManageSheet.kt | 12 +- .../ui/config/themeConfig/ThemeListDialog.kt | 2 +- .../java/io/legado/app/ui/main/MainScreen.kt | 1 - .../app/ui/main/bookshelf/BookshelfScreen.kt | 7 +- .../app/ui/main/explore/ExploreScreen.kt | 2 +- .../java/io/legado/app/ui/theme/AppTheme.kt | 3 +- .../legado/app/ui/widget/CollapsibleHeader.kt | 2 +- .../{SearchBarSection.kt => SearchBar.kt} | 16 +- .../widget/components/book/SearchBookItem.kt | 4 +- .../ui/widget/components/card/GlassCard.kt | 61 ++-- .../components/card/SelectionItemCard.kt | 5 +- .../components/explore/ExploreKindItem.kt | 6 +- .../modalBottomSheet/OptionSheet.kt | 9 +- .../components/topbar/DynamicTopAppBar.kt | 4 +- app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 28 files changed, 314 insertions(+), 266 deletions(-) rename app/src/main/java/io/legado/app/ui/widget/components/{SearchBarSection.kt => SearchBar.kt} (86%) diff --git a/app/src/main/java/io/legado/app/data/dao/ReadRecordDao.kt b/app/src/main/java/io/legado/app/data/dao/ReadRecordDao.kt index 059d4184d..152976660 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReadRecordDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReadRecordDao.kt @@ -160,6 +160,12 @@ interface ReadRecordDao { @Query("SELECT * FROM readRecordSession WHERE deviceId = :deviceId AND bookName = :bookName AND bookAuthor = :bookAuthor") suspend fun getSessionsByBook(deviceId: String, bookName: String, bookAuthor: String): List + @Query("SELECT * FROM readRecordSession WHERE deviceId = :deviceId AND bookName = :bookName AND bookAuthor = :bookAuthor ORDER BY startTime DESC") + fun getSessionsByBookFlow(deviceId: String, bookName: String, bookAuthor: String): Flow> + + @Query("SELECT readTime FROM readRecord WHERE deviceId = :deviceId AND bookName = :bookName AND bookAuthor = :bookAuthor") + fun getReadTimeFlow(deviceId: String, bookName: String, bookAuthor: String): Flow + @Delete suspend fun deleteDetail(detail: ReadRecordDetail) diff --git a/app/src/main/java/io/legado/app/data/repository/ReadRecordRepository.kt b/app/src/main/java/io/legado/app/data/repository/ReadRecordRepository.kt index 7fb86c548..0b8b074b6 100644 --- a/app/src/main/java/io/legado/app/data/repository/ReadRecordRepository.kt +++ b/app/src/main/java/io/legado/app/data/repository/ReadRecordRepository.kt @@ -7,6 +7,7 @@ import io.legado.app.data.dao.ReadRecordDao import io.legado.app.data.entities.readRecord.ReadRecord import io.legado.app.data.entities.readRecord.ReadRecordDetail import io.legado.app.data.entities.readRecord.ReadRecordSession +import io.legado.app.data.entities.readRecord.ReadRecordTimelineDay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import java.util.Date @@ -51,6 +52,27 @@ class ReadRecordRepository( return dao.getAllSessions(getCurrentDeviceId()) } + fun getBookSessions(bookName: String, bookAuthor: String): Flow> { + return dao.getSessionsByBookFlow(getCurrentDeviceId(), bookName, bookAuthor) + } + + fun getBookTimelineDays(bookName: String, bookAuthor: String): Flow> { + return getBookSessions(bookName, bookAuthor).map { sessions -> + sessions.groupBy { DateUtil.format(Date(it.startTime), "yyyy-MM-dd") } + .toSortedMap(compareByDescending { it }) + .map { (date, daySessions) -> + ReadRecordTimelineDay( + date = date, + sessions = daySessions.sortedByDescending { it.startTime } + ) + } + } + } + + fun getBookReadTime(bookName: String, bookAuthor: String): Flow { + return dao.getReadTimeFlow(getCurrentDeviceId(), bookName, bookAuthor).map { it ?: 0L } + } + suspend fun getMergeCandidates(targetRecord: ReadRecord): List { return dao.getReadRecordsByNameExcludingAuthor( targetRecord.deviceId, 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 ddfe1ec9f..bef37a4c1 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 @@ -53,7 +53,7 @@ import io.legado.app.ui.theme.adaptiveContentPadding import io.legado.app.ui.theme.adaptiveHorizontalPadding import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.EmptyMessage -import io.legado.app.ui.widget.components.SearchBarSection +import io.legado.app.ui.widget.components.SearchBar import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet import io.legado.app.ui.widget.components.bookmark.BookmarkItem import io.legado.app.ui.widget.components.button.TopBarActionButton @@ -190,7 +190,7 @@ fun AllBookmarkScreen( enter = expandVertically() + fadeIn(), exit = shrinkVertically() + fadeOut() ) { - SearchBarSection( + SearchBar( query = searchText, onQueryChange = { viewModel.onSearchQueryChanged(it) }, placeholder = "搜索...", @@ -258,7 +258,7 @@ fun AllBookmarkScreen( .animateItem() .fillMaxWidth() .padding(vertical = 4.dp), - shape = MaterialTheme.shapes.medium, + cornerRadius = 12.dp, containerColor = LegadoTheme.colorScheme.surfaceContainer ) { BookmarkGroupHeaderContent( 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 ce14b3329..79643842b 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 @@ -10,22 +10,16 @@ import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.clickable -import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.aspectRatio 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.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.grid.GridCells @@ -35,21 +29,17 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.FormatListBulleted import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.FilterList import androidx.compose.material.icons.filled.GridView -import androidx.compose.material.icons.filled.Warning import androidx.compose.material.icons.outlined.FilterAlt import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Slider -import androidx.compose.material3.Surface import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState @@ -63,14 +53,11 @@ 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.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import dev.chrisbanes.haze.HazeState import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import io.legado.app.data.entities.SearchBook @@ -81,12 +68,11 @@ import io.legado.app.ui.theme.ThemeResolver import io.legado.app.ui.theme.responsiveHazeEffect import io.legado.app.ui.theme.responsiveHazeSource import io.legado.app.ui.widget.components.AppScaffold -import io.legado.app.ui.widget.components.SearchBarSection +import io.legado.app.ui.widget.components.SearchBar import io.legado.app.ui.widget.components.button.AnimatedTextButton import io.legado.app.ui.widget.components.button.TopBarActionButton import io.legado.app.ui.widget.components.button.TopBarNavigationButton 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.explore.calculateExploreKindRows import io.legado.app.ui.widget.components.explore.ExploreKindMultiTypeItem import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu @@ -254,7 +240,7 @@ fun ExploreShowScreen( var kindQuery by remember { mutableStateOf("") } - SearchBarSection( + SearchBar( query = kindQuery, backgroundColor = LegadoTheme.colorScheme.surface.copy(alpha = 0.5f), onQueryChange = { kindQuery = it }, 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 a9540d6c8..51db6d1b3 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 @@ -564,7 +564,7 @@ private fun PathNavigationBar( GlassCard( modifier = Modifier.weight(1f), containerColor = LegadoTheme.colorScheme.surfaceContainer, - shape = MaterialTheme.shapes.medium + cornerRadius = 12.dp, ) { LazyRow( modifier = Modifier.fillMaxWidth(), 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 65bc3885c..d9024346c 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 @@ -74,7 +74,7 @@ import io.legado.app.ui.theme.adaptiveHorizontalPadding import io.legado.app.ui.widget.CollapsibleHeader import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.EmptyMessage -import io.legado.app.ui.widget.components.SearchBarSection +import io.legado.app.ui.widget.components.SearchBar import io.legado.app.ui.widget.components.alert.AppAlertDialog import io.legado.app.ui.widget.components.button.AppIconButton import io.legado.app.ui.widget.components.button.TopBarNavigationButton @@ -102,6 +102,7 @@ import io.legado.app.ui.widget.components.swipe.SwipeActionContainer import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults +import io.legado.app.utils.formatReadDuration import io.legado.app.utils.StringUtils.formatFriendlyDate import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -226,7 +227,7 @@ fun ReadRecordScreen( modifier = Modifier.adaptiveHorizontalPadding(), visible = showSearch ) { - SearchBarSection( + SearchBar( query = state.searchKey ?: "", onQueryChange = { viewModel.setSearchKey(it) } ) @@ -1044,13 +1045,5 @@ fun BookStackView(coverPaths: List) { } fun formatDuring(mss: Long): String { - val days = mss / (1000 * 60 * 60 * 24) - val hours = mss % (1000 * 60 * 60 * 24) / (1000 * 60 * 60) - val minutes = mss % (1000 * 60 * 60) / (1000 * 60) - val seconds = mss % (1000 * 60) / 1000 - val d = if (days > 0) "${days}天" else "" - val h = if (hours > 0) "${hours}小时" else "" - val m = if (minutes > 0) "${minutes}分钟" else "" - val s = if (seconds > 0) "${seconds}秒" else "" - return if ("$d$h$m$s".isBlank()) "0秒" else "$d$h$m$s" + return formatReadDuration(mss) } diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchScreen.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchScreen.kt index 26b5d7366..096c10c99 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchScreen.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.book.search +import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -10,6 +11,7 @@ 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.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow @@ -68,15 +70,15 @@ import io.legado.app.ui.theme.adaptiveContentPadding import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical import io.legado.app.ui.theme.adaptiveHorizontalPadding import io.legado.app.ui.widget.components.AppFloatingActionButton -import io.legado.app.ui.widget.components.AppSearchBar import io.legado.app.ui.widget.components.AppScaffold +import io.legado.app.ui.widget.components.SearchBar import io.legado.app.ui.widget.components.alert.AppAlertDialog import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet import io.legado.app.ui.widget.components.book.SearchBookListItem import io.legado.app.ui.widget.components.button.SmallIconButton import io.legado.app.ui.widget.components.button.SmallTextButton +import io.legado.app.ui.widget.components.card.NormalCard import io.legado.app.ui.widget.components.card.SelectionItemCard -import io.legado.app.ui.widget.components.card.TextCard import io.legado.app.ui.widget.components.button.ToggleChip import io.legado.app.ui.widget.components.button.TopBarActionButton import io.legado.app.ui.widget.components.button.TopBarAnimatedActionButton @@ -84,6 +86,7 @@ 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.icon.AppIcon import io.legado.app.ui.widget.components.icon.AppIcons +import io.legado.app.ui.widget.components.list.TopFloatingStickyItem import io.legado.app.ui.widget.components.tabRow.AppTabRow import io.legado.app.ui.widget.components.text.AppText import io.legado.app.utils.toastOnUi @@ -104,8 +107,8 @@ fun SearchScreen( val state by viewModel.uiState.collectAsStateWithLifecycle() val listState = rememberLazyListState() var queryInput by rememberSaveable { mutableStateOf(state.query) } - var searchExpanded by rememberSaveable { mutableStateOf(false) } var scopeSheetTab by rememberSaveable { mutableStateOf(0) } + val showSuggestionPanel = state.showSuggestions val latestQuery by rememberUpdatedState(state.query) val scrollBehavior = if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) { GlassTopAppBarDefaults.defaultScrollBehavior() @@ -149,15 +152,13 @@ fun SearchScreen( state.hasMore, state.isManualStop, state.showSuggestions, - searchExpanded, ) { if ( shouldLoadMore && !state.isSearching && state.hasMore && !state.isManualStop && - !state.showSuggestions && - !searchExpanded + !state.showSuggestions ) { viewModel.onIntent(SearchIntent.LoadMore) } @@ -203,104 +204,60 @@ fun SearchScreen( ) }, actions = { - if (!searchExpanded) { - TopBarActionButton( - onClick = { - viewModel.onIntent(SearchIntent.SetScopeSheetVisible(true)) - }, - imageVector = AppIcons.Filter - ) - TopBarActionButton( - onClick = { - viewModel.onIntent(SearchIntent.OpenSourceManage) - }, - imageVector = AppIcons.Settings, - ) - } + TopBarAnimatedActionButton( + checked = state.isPrecisionSearch, + onCheckedChange = { checked -> + viewModel.onIntent(SearchIntent.TogglePrecision(checked)) + }, + iconChecked = AppIcons.PrecisionSearch, + iconUnchecked = AppIcons.UnPrecisionSearch, + activeText = stringResource(R.string.precision_search), + inactiveText = stringResource(R.string.search), + ) + TopBarActionButton( + onClick = { + viewModel.onIntent(SearchIntent.SetScopeSheetVisible(true)) + }, + imageVector = AppIcons.Filter + ) + TopBarActionButton( + onClick = { + viewModel.onIntent(SearchIntent.OpenSourceManage) + }, + imageVector = AppIcons.Settings, + ) }, scrollBehavior = scrollBehavior ) Spacer(modifier = Modifier.height(8.dp)) - AppSearchBar( - modifier = Modifier.fillMaxWidth(), - query = queryInput, - onQueryChange = { queryInput = it }, - onSearch = submitSearch, - expanded = searchExpanded, - onExpandedChange = { searchExpanded = it }, - label = searchLabel, - placeholder = { Text(text = searchLabel) }, - leadingIcon = { - TopBarActionButton( - onClick = { - if (searchExpanded) { - searchExpanded = false - } - }, - imageVector = if (searchExpanded) AppIcons.Back else AppIcons.Search, - contentDescription = if (searchExpanded) stringResource(R.string.search) else stringResource( - R.string.search - ) - ) - }, - trailingIcon = { - Row(verticalAlignment = Alignment.CenterVertically) { - if (queryInput.isNotEmpty()) { - TopBarActionButton( - onClick = { - queryInput = "" - viewModel.onIntent(SearchIntent.UpdateQuery("")) - }, - imageVector = Icons.Default.Close, - contentDescription = stringResource(R.string.clear) - ) - } - TopBarAnimatedActionButton( - checked = state.isPrecisionSearch, - onCheckedChange = { checked -> - viewModel.onIntent(SearchIntent.TogglePrecision(checked)) - }, - iconChecked = AppIcons.PrecisionSearch, - iconUnchecked = AppIcons.UnPrecisionSearch, - activeText = stringResource(R.string.precision_search), - inactiveText = stringResource(R.string.search), - ) - if (searchExpanded) { - TopBarActionButton( - onClick = { - viewModel.onIntent(SearchIntent.SetScopeSheetVisible(true)) - }, - imageVector = AppIcons.Filter, - contentDescription = stringResource(R.string.search_select_group) - ) - TopBarActionButton( - onClick = { - viewModel.onIntent(SearchIntent.OpenSourceManage) - }, - imageVector = AppIcons.Settings, - contentDescription = stringResource(R.string.book_source_manage) - ) - } - } - }, + Box( + modifier = Modifier + .fillMaxWidth() + .adaptiveHorizontalPadding() ) { - SearchSuggestionPanel( - state = state, - onUseHistory = { keyword -> - queryInput = keyword - viewModel.onIntent(SearchIntent.UseHistoryKeyword(keyword)) - searchExpanded = false + SearchBar( + query = queryInput, + onQueryChange = { queryInput = it }, + onSearch = submitSearch, + placeholder = searchLabel, + trailingIcon = { + Row( + modifier = Modifier.padding(end = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (queryInput.isNotEmpty()) { + TopBarActionButton( + onClick = { + queryInput = "" + viewModel.onIntent(SearchIntent.UpdateQuery("")) + }, + imageVector = AppIcons.Close, + contentDescription = stringResource(R.string.clear) + ) + } + } }, - onDeleteHistory = { viewModel.onIntent(SearchIntent.DeleteHistory(it)) }, - onOpenBook = { - viewModel.onIntent(SearchIntent.OpenBookshelfBook(it)) - searchExpanded = false - }, - onClearHistory = { - viewModel.onIntent(SearchIntent.SetClearHistoryDialogVisible(true)) - }, - modifier = Modifier.fillMaxSize(), ) } } @@ -330,73 +287,113 @@ fun SearchScreen( .fillMaxSize() .padding(paddingValues) ) { - if (showResultCountCard || showSourceProgressCard) { - Spacer(modifier = Modifier.height(6.dp)) - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 36.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - if (showResultCountCard) { - TextCard( - modifier = Modifier.weight(1f), - icon = AppIcons.Search, - text = "搜索结果 ${state.results.size}" - ) - } - if (showSourceProgressCard) { - TextCard( - modifier = Modifier.weight(1f), - icon = AppIcons.Filter, - text = "已检索源 ${state.processedSources}/${state.totalSources}" - ) - } - } - } - - Spacer(modifier = Modifier.height(8.dp)) - - if (state.results.isEmpty()) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - SearchResultFooter( - isSearching = state.isSearching, - hasMore = state.hasMore, - hasResult = false, - committedQuery = state.committedQuery, - onLoadMore = { viewModel.onIntent(SearchIntent.LoadMore) }, + AnimatedContent( + targetState = showSuggestionPanel, + label = "SearchBodyTransition", + modifier = Modifier.fillMaxSize() + ) { isSuggestionVisible -> + if (isSuggestionVisible) { + SearchSuggestionPanel( + state = state, + onUseHistory = { keyword -> + queryInput = keyword + viewModel.onIntent(SearchIntent.UseHistoryKeyword(keyword)) + }, + onDeleteHistory = { viewModel.onIntent(SearchIntent.DeleteHistory(it)) }, + onOpenBook = { + viewModel.onIntent(SearchIntent.OpenBookshelfBook(it)) + }, + onClearHistory = { + viewModel.onIntent(SearchIntent.SetClearHistoryDialogVisible(true)) + }, + modifier = Modifier.fillMaxSize(), ) - } - } else { - LazyColumn( - modifier = Modifier.fillMaxSize(), - state = listState, - verticalArrangement = Arrangement.spacedBy(6.dp) - ) { - items(items = state.results, key = { it.bookUrl }) { book -> - val shelfStateFlow = remember(book.bookUrl) { - viewModel.getBookShelfStateFlow(book) - } - SearchBookListItem( - book = book, - shelfState = shelfStateFlow, - onClick = { - viewModel.onIntent(SearchIntent.OpenSearchBook(book)) - } - ) - } + } else { + Box(modifier = Modifier.fillMaxSize()) { + Column(modifier = Modifier.fillMaxSize()) { + Spacer(modifier = Modifier.height(8.dp)) - item { - SearchResultFooter( - isSearching = state.isSearching, - hasMore = state.hasMore, - hasResult = true, - committedQuery = state.committedQuery, - onLoadMore = { viewModel.onIntent(SearchIntent.LoadMore) }, - ) + if (state.results.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + SearchResultFooter( + isSearching = state.isSearching, + hasMore = state.hasMore, + hasResult = false, + committedQuery = state.committedQuery, + onLoadMore = { viewModel.onIntent(SearchIntent.LoadMore) }, + ) + } + } + } + + if (state.results.isNotEmpty()) { + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = listState, + contentPadding = adaptiveContentPaddingOnlyVertical( + top = 48.dp, + bottom = 8.dp + ), + verticalArrangement = Arrangement.spacedBy(6.dp) + ) { + items(items = state.results, key = { it.bookUrl }) { book -> + val shelfStateFlow = remember(book.bookUrl) { + viewModel.getBookShelfStateFlow(book) + } + SearchBookListItem( + book = book, + shelfState = shelfStateFlow, + onClick = { + viewModel.onIntent(SearchIntent.OpenSearchBook(book)) + } + ) + } + + item { + SearchResultFooter( + isSearching = state.isSearching, + hasMore = state.hasMore, + hasResult = true, + committedQuery = state.committedQuery, + onLoadMore = { viewModel.onIntent(SearchIntent.LoadMore) }, + ) + } + } + } + + TopFloatingStickyItem( + item = if (showResultCountCard || showSourceProgressCard) { + SearchFloatingSummary( + resultText = if (showResultCountCard) "结果 ${state.results.size}" else null, + sourceText = if (showSourceProgressCard) " · 进度 ${state.processedSources}/${state.totalSources}" else null, + ) + } else { + null + }, + modifier = Modifier + .align(Alignment.TopCenter) + .padding(top = 6.dp), + ) { summary -> + NormalCard( + cornerRadius = 16.dp, + containerColor = LegadoTheme.colorScheme.surfaceContainer, + contentColor = LegadoTheme.colorScheme.onCardContainer + ) { + Row( + modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp), + ) { + summary.resultText?.let { text -> + AppText(text = text, style = LegadoTheme.typography.labelSmallEmphasized) + } + summary.sourceText?.let { text -> + AppText(text = text, style = LegadoTheme.typography.labelSmallEmphasized) + } + } + } + } } } } @@ -520,6 +517,11 @@ fun SearchScreen( } } +private data class SearchFloatingSummary( + val resultText: String?, + val sourceText: String?, +) + @Composable private fun SearchSuggestionPanel( state: SearchUiState, @@ -565,7 +567,10 @@ private fun SearchSuggestionPanel( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, ) { - Row(verticalAlignment = Alignment.CenterVertically) { + Row( + modifier = Modifier.padding(vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { AppIcon(AppIcons.History, contentDescription = null) Spacer(modifier = Modifier.width(6.dp)) AppText( @@ -636,9 +641,16 @@ private fun SearchResultFooter( ) { when { isSearching -> { - Row(verticalAlignment = Alignment.CenterVertically) { - CircularProgressIndicator(modifier = Modifier.width(18.dp), strokeWidth = 2.dp) - Spacer(modifier = Modifier.width(8.dp)) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + Box( + modifier = Modifier.size(18.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } AppText(text = stringResource(R.string.is_loading)) } } 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 88f387085..3d0aff56e 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 @@ -59,7 +59,7 @@ import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.adaptiveHorizontalPadding import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.EmptyMessage -import io.legado.app.ui.widget.components.SearchBarSection +import io.legado.app.ui.widget.components.SearchBar import io.legado.app.ui.widget.components.button.MediumOutlinedButton import io.legado.app.ui.widget.components.button.SmallAnimatedActionButton import io.legado.app.ui.widget.components.button.SmallIconButton @@ -167,7 +167,7 @@ fun SearchContentScreen( Box( modifier = Modifier.adaptiveHorizontalPadding() ) { - SearchBarSection( + SearchBar( query = searchQuery, scrollState = listState, onQueryChange = { viewModel.onQueryChange(it) } 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 515c654b5..8a8722f3e 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 @@ -104,6 +104,7 @@ import io.legado.app.ui.widget.components.SelectionBottomBar import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet import io.legado.app.ui.widget.components.bookmark.BookmarkItem import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton +import io.legado.app.ui.widget.components.card.NormalCard import io.legado.app.ui.widget.components.card.TextCard import io.legado.app.ui.widget.components.divider.PillDivider import io.legado.app.ui.widget.components.divider.PillHeaderDivider @@ -950,13 +951,13 @@ private fun StatusIcon( } "SUCCESS_WORD_COUNT" -> { - Surface( - shape = MaterialTheme.shapes.medium, + NormalCard( + cornerRadius = 12.dp, border = BorderStroke( 1.dp, LegadoTheme.colorScheme.outlineVariant ), - color = Color.Transparent + containerColor = Color.Transparent ) { if (wordCount != null) { AppText( 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 6fc5536d0..276592f42 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 @@ -36,7 +36,9 @@ import coil.compose.AsyncImage import io.legado.app.R import io.legado.app.constant.PreferKey import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.widget.components.card.NormalCard import io.legado.app.ui.widget.components.filePicker.FilePickerSheet +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 @@ -87,9 +89,8 @@ fun CoverManageSheet( ) { items(coverList) { path -> Box { - Surface( - shape = MaterialTheme.shapes.medium, - tonalElevation = 2.dp + NormalCard( + cornerRadius = 12.dp ) { AsyncImage( model = path, @@ -122,16 +123,16 @@ fun CoverManageSheet( } item { - Surface( + NormalCard( onClick = { showFilePicker = true }, - shape = MaterialTheme.shapes.medium, - color = MaterialTheme.colorScheme.surfaceContainerHigh, + cornerRadius = 12.dp, + containerColor = LegadoTheme.colorScheme.surfaceContainerHigh, modifier = Modifier .fillMaxWidth() .aspectRatio(0.7f) ) { Box(contentAlignment = Alignment.Center) { - Icon( + AppIcon( imageVector = Icons.Default.Add, contentDescription = "Add", modifier = Modifier.size(32.dp), 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 a4e5add30..6eb8affa7 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,6 +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.button.SmallTonalIconButton +import io.legado.app.ui.widget.components.card.NormalCard import io.legado.app.ui.widget.components.filePicker.FilePickerSheet import io.legado.app.ui.widget.components.icon.AppIcon import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet @@ -80,10 +81,10 @@ fun BackgroundImageManageSheet( ) { if (currentPath.isNullOrBlank()) { - Surface( + NormalCard( onClick = { showFilePicker = true }, - shape = MaterialTheme.shapes.medium, - color = LegadoTheme.colorScheme.surfaceContainerHigh, + cornerRadius = 12.dp, + containerColor = LegadoTheme.colorScheme.surfaceContainerHigh, modifier = Modifier .fillMaxWidth() .aspectRatio(16f / 9f) @@ -104,9 +105,8 @@ fun BackgroundImageManageSheet( .fillMaxWidth() .padding(16.dp) ) { - Surface( - shape = MaterialTheme.shapes.medium, - tonalElevation = 2.dp + NormalCard( + cornerRadius = 12.dp, ) { AsyncImage( model = currentPath, 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 c5310591a..ee0ac0175 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 @@ -92,7 +92,7 @@ fun ThemeListDialog( }, modifier = Modifier .fillMaxWidth(), - shape = RoundedCornerShape(20.dp), + cornerRadius = 20.dp, containerColor = if (item.primaryColor.toColorInt() == context.primaryColor) { MaterialTheme.colorScheme.secondaryContainer } else { 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 8b630f537..11251605d 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 @@ -315,7 +315,6 @@ fun MainScreen( AppNavigationBar( modifier = Modifier .regularHazeEffect(state = hazeState) - .height(if (isUnlabeled) 64.dp else 80.dp) ) { destinations.forEachIndexed { index, destination -> val selected = pagerState.targetPage == index 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 07819b6f1..1f02a82d0 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 @@ -77,6 +77,7 @@ import io.legado.app.ui.theme.adaptiveHorizontalPadding import io.legado.app.ui.theme.adaptiveHorizontalPaddingTab import io.legado.app.ui.widget.components.EmptyMessage import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton +import io.legado.app.ui.widget.components.card.NormalCard import io.legado.app.ui.widget.components.filePicker.FilePickerSheet import io.legado.app.ui.widget.components.importComponents.SourceInputDialog import io.legado.app.ui.widget.components.lazylist.FastScrollLazyVerticalGrid @@ -568,9 +569,9 @@ fun BookshelfScreen( if (uiState.isLoading) { Dialog(onDismissRequest = {}) { - Surface( - shape = MaterialTheme.shapes.medium, - color = MaterialTheme.colorScheme.surfaceContainerHigh + NormalCard( + cornerRadius = 12.dp, + containerColor = LegadoTheme.colorScheme.surfaceContainerHigh ) { Column( modifier = Modifier.padding(24.dp), 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 bce917616..528155752 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 @@ -345,7 +345,7 @@ fun ExploreSourceHeader( modifier = modifier .fillMaxWidth() .padding(vertical = 4.dp), - shape = MaterialTheme.shapes.medium, + cornerRadius = 12.dp, containerColor = containerColor ) { ListItem( 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 1c328c0c8..84ce11145 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 @@ -180,7 +180,8 @@ fun AppTheme( surfaceContainer = miuixColorScheme.surfaceContainer, surfaceContainerHigh = miuixColorScheme.surfaceContainerHigh, surfaceContainerHighest = miuixColorScheme.surfaceContainerHighest, - surfaceContainerLow = miuixColorScheme.secondaryContainer, + surfaceContainerLow = miuixColorScheme.secondaryContainer.copy(alpha = 0.32f) + .compositeOver(miuixColorScheme.surface), surfaceContainerLowest = miuixColorScheme.background, primaryFixed = miuixColorScheme.primaryContainer, 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 1bc32f113..f3b765d6c 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 @@ -39,7 +39,7 @@ fun CollapsibleHeader( modifier = modifier .fillMaxWidth() .adaptiveHorizontalPadding(vertical = 4.dp), - shape = MaterialTheme.shapes.medium, + cornerRadius = 12.dp, containerColor = LegadoTheme.colorScheme.surfaceContainer, onClick = onToggle ) { 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/SearchBar.kt similarity index 86% rename from app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt rename to app/src/main/java/io/legado/app/ui/widget/components/SearchBar.kt index 118e3c33d..acf72d21f 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/SearchBar.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.input.TextFieldLineLimits import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.material3.ExperimentalMaterial3Api @@ -15,6 +16,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver @@ -26,10 +28,11 @@ import top.yukonga.miuix.kmp.theme.MiuixTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun SearchBarSection( +fun SearchBar( modifier: Modifier = Modifier, query: String, onQueryChange: (String) -> Unit, + onSearch: (String) -> Unit = {}, placeholder: String = "搜索...", leadingIcon: @Composable (() -> Unit)? = { AppIcon( @@ -79,10 +82,15 @@ fun SearchBarSection( placeholder = { AppText(placeholder) }, leadingIcon = leadingIcon, trailingIcon = trailingIcon, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), + onKeyboardAction = { + onSearch(textFieldState.text.toString()) + }, lineLimits = TextFieldLineLimits.SingleLine, backgroundColor = resolvedBackgroundColor, miuixUseSearchBarInputField = true, - miuixSearchBarLabel = placeholder + miuixSearchBarLabel = placeholder, + miuixOnSearch = onSearch, ) } else { Surface( @@ -98,6 +106,10 @@ fun SearchBarSection( placeholder = { AppText(placeholder) }, leadingIcon = leadingIcon, trailingIcon = trailingIcon, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), + onKeyboardAction = { + onSearch(textFieldState.text.toString()) + }, lineLimits = TextFieldLineLimits.SingleLine, backgroundColor = Color.Transparent ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/book/SearchBookItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/book/SearchBookItem.kt index 53456a097..aee32bf59 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/book/SearchBookItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/book/SearchBookItem.kt @@ -17,6 +17,8 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Shuffle +import androidx.compose.material.icons.filled.SwapHoriz import androidx.compose.material.icons.filled.Warning import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -59,7 +61,7 @@ fun SearchBookListItem( BookShelfState.SAME_NAME_AUTHOR -> { { androidx.compose.material3.Icon( - imageVector = Icons.Default.Warning, + imageVector = Icons.Default.Shuffle, contentDescription = "同名书籍", modifier = Modifier.size(12.dp), ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt index 69680e3cc..0ed846a39 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/card/GlassCard.kt @@ -1,17 +1,20 @@ package io.legado.app.ui.widget.components.card import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.CardElevation +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import io.legado.app.ui.config.themeConfig.ThemeConfig import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver @@ -25,12 +28,12 @@ import top.yukonga.miuix.kmp.basic.CardDefaults as MiuixCardDefaults private fun BaseCard( modifier: Modifier = Modifier, onClick: (() -> Unit)? = null, - shape: Shape = CardDefaults.shape, + onLongClick: (() -> Unit)? = null, cornerRadius: Dp = MiuixCardDefaults.CornerRadius, pressFeedbackType: PressFeedbackType = PressFeedbackType.None, containerColor: Color? = null, contentColor: Color? = null, - elevation: CardElevation = CardDefaults.cardElevation(), + elevation: Dp = 0.dp, border: BorderStroke? = null, alpha: Float = 1f, content: @Composable ColumnScope.() -> Unit @@ -47,6 +50,7 @@ private fun BaseCard( pressFeedbackType = pressFeedbackType, showIndication = true, onClick = onClick, + onLongPress = onLongClick, content = content, colors = colors ) @@ -67,25 +71,26 @@ private fun BaseCard( disabledContainerColor = LegadoTheme.colorScheme.onSecondaryContainer.copy(alpha = alpha * 0.38f), disabledContentColor = LegadoTheme.colorScheme.onSecondaryContainer.copy(alpha = alpha * 0.38f) ) - if (onClick != null) { - Card( - modifier = modifier, - shape = RoundedCornerShape(cornerRadius), - colors = colors, - elevation = elevation, - border = border, - onClick = onClick, - content = content - ) + val clickableModifier = if (onClick != null || onLongClick != null) { + modifier + .clip(RoundedCornerShape(cornerRadius)) + .combinedClickable( + onClick = { onClick?.invoke() }, + onLongClick = onLongClick + ) } else { - Card( - modifier = modifier, - shape = RoundedCornerShape(cornerRadius), - colors = colors, - elevation = elevation, - border = border, - content = content - ) + modifier + } + Surface( + modifier = clickableModifier, + shape = RoundedCornerShape(cornerRadius), + color = colors.containerColor, + contentColor = colors.contentColor, + tonalElevation = 0.dp, + shadowElevation = elevation, + border = border + ) { + Column(content = content) } } } @@ -95,19 +100,19 @@ private fun BaseCard( fun GlassCard( modifier: Modifier = Modifier, onClick: (() -> Unit)? = null, - shape: Shape = CardDefaults.shape, + onLongClick: (() -> Unit)? = null, cornerRadius: Dp = MiuixCardDefaults.CornerRadius, pressFeedbackType: PressFeedbackType = PressFeedbackType.None, containerColor: Color? = null, contentColor: Color? = null, - elevation: CardElevation = CardDefaults.cardElevation(), + elevation: Dp = 0.dp, border: BorderStroke? = null, content: @Composable ColumnScope.() -> Unit ) { BaseCard( modifier = modifier, onClick = onClick, - shape = shape, + onLongClick = onLongClick, cornerRadius = cornerRadius, pressFeedbackType = pressFeedbackType, containerColor = containerColor, @@ -124,19 +129,19 @@ fun GlassCard( fun NormalCard( modifier: Modifier = Modifier, onClick: (() -> Unit)? = null, - shape: Shape = CardDefaults.shape, + onLongClick: (() -> Unit)? = null, cornerRadius: Dp = MiuixCardDefaults.CornerRadius, pressFeedbackType: PressFeedbackType = PressFeedbackType.None, containerColor: Color? = null, contentColor: Color? = null, - elevation: CardElevation = CardDefaults.cardElevation(), + elevation: Dp = 0.dp, border: BorderStroke? = null, content: @Composable ColumnScope.() -> Unit ) { BaseCard( modifier = modifier, onClick = onClick, - shape = shape, + onLongClick = onLongClick, cornerRadius = cornerRadius, pressFeedbackType = pressFeedbackType, containerColor = containerColor, 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 a1c51184e..0560ef3c8 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 @@ -19,7 +19,6 @@ import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.MoreVert -import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemDefaults @@ -88,9 +87,9 @@ fun SelectionItemCard( onClick = onToggleSelection, modifier = modifier .fillMaxWidth(), - shape = MaterialTheme.shapes.medium, + cornerRadius = 12.dp, containerColor = animatedContainerColor, - elevation = CardDefaults.cardElevation(defaultElevation = elevation) + elevation = elevation ) { SelectionItemCardContent( title = title, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/explore/ExploreKindItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/explore/ExploreKindItem.kt index ea4c12de4..acc69d799 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/explore/ExploreKindItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/explore/ExploreKindItem.kt @@ -36,12 +36,12 @@ fun ExploreKindItem( LocalMinimumInteractiveComponentSize provides Dp.Unspecified ) { - val shape = MaterialTheme.shapes.medium + val cornerRadius = 12.dp if (isClickable) { GlassCard( onClick = onClick, - shape = shape, + cornerRadius = cornerRadius, containerColor = backgroundColor, contentColor = LegadoTheme.colorScheme.onSurface, modifier = modifier @@ -54,7 +54,7 @@ fun ExploreKindItem( } } else { GlassCard( - shape = shape, + cornerRadius = cornerRadius, containerColor = backgroundColor, contentColor = LegadoTheme.colorScheme.primary, modifier = modifier, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt index 439204cf4..8e5634d30 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.widget.components.card.NormalCard import io.legado.app.ui.widget.components.icon.AppIcon import io.legado.app.ui.widget.components.text.AppText @@ -58,14 +59,14 @@ fun RowScope.OptionCard( text: String, onClick: () -> Unit ) { - Surface( + NormalCard( onClick = onClick, modifier = Modifier .weight(1f) .height(100.dp), - shape = MaterialTheme.shapes.medium, - color = LegadoTheme.colorScheme.surfaceContainerLow, - tonalElevation = 2.dp + cornerRadius = 12.dp, + containerColor = LegadoTheme.colorScheme.surfaceContainerLow, + elevation = 2.dp ) { Column( modifier = Modifier.fillMaxSize(), 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 95d482aff..9cf54d87b 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 @@ -21,7 +21,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import io.legado.app.ui.theme.adaptiveHorizontalPadding -import io.legado.app.ui.widget.components.SearchBarSection +import io.legado.app.ui.widget.components.SearchBar 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 @@ -107,7 +107,7 @@ fun DynamicTopAppBar( enter = expandVertically() + fadeIn(), exit = shrinkVertically() + fadeOut() ) { - SearchBarSection( + SearchBar( query = state.searchKey, onQueryChange = onSearchQueryChange, placeholder = searchPlaceholder, diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 65173df21..203066608 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -246,6 +246,7 @@ 更新和搜索线程数 切换图标 已在书架 + 已在书架 开始阅读 加载数据中… 加载失败 @@ -395,6 +396,7 @@ 导航栏颜色透明 放入书架 点击删除 + 长按分组 继续阅读 封面地址 覆盖 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index c738ceafa..58f82fe7f 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -223,6 +223,7 @@ 更新/搜尋線程數,太多會卡頓 切換圖標 刪除書輯 + 已在書架 開始閲讀 數據載入中… 載入失敗,點擊重試 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 949e14641..5197f7e0e 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -225,6 +225,7 @@ 更新和搜尋執行緒數,太多會卡頓 切換圖示 刪除書籍 + 已在書架 開始閱讀 載入資料中… 載入失敗,點擊重試 @@ -373,6 +374,7 @@ 導航欄顏色透明 放入書架 點擊刪除 + 長按分組 繼續閱讀 封面地址 覆蓋 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9f76bba2c..7d1ebe74d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -249,6 +249,7 @@ Number of concurrent tasks Change icon In library + Already in Bookshelf Start reading Loading… Load failed, tap to retry @@ -398,6 +399,7 @@ The navigation bar becomes transparent Add to Bookshelf Tap to remove + Long press to group Continue reading Cover path Cover