From 210eef600c41e30c1fc6283ae61e83c8b5944444 Mon Sep 17 00:00:00 2001 From: yukonisen Date: Wed, 25 Dec 2024 18:03:31 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=8E=A2=E7=B4=A2=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E3=80=81=E6=90=9C=E7=B4=A2=E7=BB=93=E6=9E=9C=E5=92=8C?= =?UTF-8?q?=E4=BA=8C=E7=BA=A7=E9=A1=B5=E9=9D=A2UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 +- .../bookshelf/home/BookshelfHomeScreen.kt | 7 -- .../bookshelf/home/BookshelfUIComponents.kt | 34 ++++-- .../ui/home/exploration/Exploration.kt | 88 +------------- .../expanded/ExpandedPageScreen.kt | 19 +-- .../exploration/home/ExplorationHomeScreen.kt | 112 +++++++++++++----- .../search/ExplorationSearchScreen.kt | 88 ++++++++------ .../lightnovelreader/utils/Haptic.kt | 16 +++ app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 190 insertions(+), 178 deletions(-) create mode 100644 app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/utils/Haptic.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b08a162..f6722ce 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,7 +21,7 @@ android { minSdk = 24 targetSdk = 34 // 版本号为x.y.z则versionCode为x*1000000+y*10000+z*100+debug版本号(开发需要时迭代, 两位数) - versionCode = 1_00_00_011 + versionCode = 1_00_00_012 versionName = "1.0.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfHomeScreen.kt b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfHomeScreen.kt index f3e76f3..421fb6c 100644 --- a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfHomeScreen.kt +++ b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfHomeScreen.kt @@ -61,12 +61,10 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -117,7 +115,6 @@ fun BookshelfHomeScreen( ) { val scope = rememberCoroutineScope() val context = LocalContext.current - val haptic = LocalHapticFeedback.current val workManager = WorkManager.getInstance(context) val enterAlwaysScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val animatedBackgroundColor by animateColorAsState( @@ -276,7 +273,6 @@ fun BookshelfHomeScreen( val onLongPress: (Int) -> Unit = { bookId -> onClickEnableSelectMode.invoke() changeBookSelectState(bookId) - haptic.performHapticFeedback(HapticFeedbackType.LongPress) } LazyColumn( @@ -302,7 +298,6 @@ fun BookshelfHomeScreen( uiState.bookInformationMap[updatedBookId]?.let { BookCardItem( bookInformation = it, - haptic = haptic, selected = uiState.selectedBookIds.contains(it.id), latestChapterTitle = uiState.bookLastChapterTitleMap[updatedBookId], onClick = { @@ -331,7 +326,6 @@ fun BookshelfHomeScreen( uiState.bookInformationMap[pinnedBookId]?.let { BookCardItem( bookInformation = it, - haptic = haptic, selected = uiState.selectedBookIds.contains(it.id), onClick = { if (!uiState.selectMode) @@ -359,7 +353,6 @@ fun BookshelfHomeScreen( uiState.bookInformationMap[bookId]?.let { BookCardItem( bookInformation = it, - haptic = haptic, selected = uiState.selectedBookIds.contains(it.id), onClick = { if (!uiState.selectMode) diff --git a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfUIComponents.kt b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfUIComponents.kt index 1cb2072..1639867 100644 --- a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfUIComponents.kt +++ b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/bookshelf/home/BookshelfUIComponents.kt @@ -35,7 +35,6 @@ import androidx.compose.material3.SwipeToDismissBoxValue.EndToStart import androidx.compose.material3.SwipeToDismissBoxValue.Settled import androidx.compose.material3.SwipeToDismissBoxValue.StartToEnd import androidx.compose.material3.Text -import androidx.compose.material3.rememberSwipeToDismissBoxState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -43,11 +42,12 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.hapticfeedback.HapticFeedback import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -59,10 +59,12 @@ import indi.dmzz_yyhyy.lightnovelreader.R import indi.dmzz_yyhyy.lightnovelreader.data.book.BookInformation import indi.dmzz_yyhyy.lightnovelreader.ui.components.Cover import indi.dmzz_yyhyy.lightnovelreader.utils.SwipeAction +import indi.dmzz_yyhyy.lightnovelreader.utils.withHaptic @Composable fun BookCardContent( selected: Boolean, + collected: Boolean, modifier: Modifier = Modifier, bookInformation: BookInformation, latestChapterTitle: String? = null @@ -84,7 +86,7 @@ fun BookCardContent( url = bookInformation.coverUrl, rounded = 8.dp ) - if (latestChapterTitle != null) { + if (latestChapterTitle != null) { // 有可用更新 Badge Box( modifier = Modifier.padding(4.dp) .align(Alignment.TopEnd) @@ -95,6 +97,22 @@ fun BookCardContent( ) } } + if (collected) { + Box( + modifier = Modifier.padding(4.dp) + .align(Alignment.TopStart) + .size(20.dp) + .clip(RoundedCornerShape(4.dp)) + .background(MaterialTheme.colorScheme.secondaryContainer) + ) { + Icon( + modifier = Modifier.scale(0.75f, 0.75f), + painter = painterResource(R.drawable.filled_bookmark_24px), + contentDescription = "collected_indicator", + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } } androidx.compose.animation.AnimatedVisibility( @@ -136,10 +154,11 @@ fun BookCardContent( val titleLineHeight = 20.sp Text( modifier = Modifier.height( - with(LocalDensity.current) { (titleLineHeight * 2).toDp() } + with(LocalDensity.current) { (titleLineHeight * 2.2f).toDp() } ).wrapContentHeight(Alignment.CenterVertically), text = bookInformation.title, maxLines = 2, + overflow = TextOverflow.Ellipsis, fontWeight = FontWeight.Bold, fontSize = 16.sp, lineHeight = titleLineHeight, @@ -254,15 +273,15 @@ fun BookCardItem( modifier: Modifier = Modifier, bookInformation: BookInformation, selected: Boolean = false, + collected: Boolean = false, onClick: () -> Unit, onLongPress: () -> Unit, latestChapterTitle: String? = null, swipeToRightAction: SwipeAction = SwipeAction.None, swipeToLeftAction: SwipeAction = SwipeAction.None, progress: (SwipeAction) -> Unit?, - haptic: HapticFeedback ){ - + val haptic = LocalHapticFeedback.current val dismissState = rememberNoFlingSwipeToDismissBoxState( positionalThreshold = { it * 0.6f }, confirmValueChange = { @@ -312,11 +331,12 @@ fun BookCardItem( .background(backgroundColor) .combinedClickable( onClick = onClick, - onLongClick = onLongPress, + onLongClick = withHaptic { onLongPress() }, ) ) { BookCardContent( selected = selected, + collected = collected, latestChapterTitle = latestChapterTitle, bookInformation = bookInformation ) diff --git a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/Exploration.kt b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/Exploration.kt index bcc5f9a..e9a90a0 100644 --- a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/Exploration.kt +++ b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/Exploration.kt @@ -3,22 +3,15 @@ package indi.dmzz_yyhyy.lightnovelreader.ui.home.exploration import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar @@ -31,17 +24,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource 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 androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import indi.dmzz_yyhyy.lightnovelreader.R -import indi.dmzz_yyhyy.lightnovelreader.data.book.BookInformation import indi.dmzz_yyhyy.lightnovelreader.ui.Screen -import indi.dmzz_yyhyy.lightnovelreader.ui.components.Cover import indi.dmzz_yyhyy.lightnovelreader.ui.components.EmptyPage import indi.dmzz_yyhyy.lightnovelreader.ui.components.NavItem import indi.dmzz_yyhyy.lightnovelreader.ui.home.exploration.expanded.ExpandedPageScreen @@ -143,7 +131,7 @@ fun Exploration( ExplorationSearchScreen( topBar = topBar, requestAddBookToBookshelf = requestAddBookToBookshelf, - onCLickBack = { navController.popBackStack() }, + onClickBack = { navController.popBackStack() }, init = explorationSearchViewModel::init, onChangeSearchType = { explorationSearchViewModel.changeSearchType(it) }, onSearch = { explorationSearchViewModel.search(it) }, @@ -177,78 +165,4 @@ fun Exploration( } } } -} - -@Composable -fun ExplorationBookCard( - modifier: Modifier = Modifier, - bookInformation: BookInformation, - allBookshelfBookIds: List, - requestAddBookToBookshelf: (Int) -> Unit, - onClickBook: (Int) -> Unit -) { - Row( - modifier = modifier - .height(125.dp) - .clickable { - onClickBook(bookInformation.id) - } - ) { - Cover( - width = 82.dp, - height = 125.dp, - url = bookInformation.coverUrl, - rounded = 8.dp - ) - Column ( - modifier = Modifier - .fillMaxWidth() - .padding(8.dp, 2.dp, 14.dp, 5.dp), - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Row( - modifier = Modifier.fillMaxWidth() - ) { - Text( - modifier = Modifier.weight(2f), - text = bookInformation.title, - style = MaterialTheme.typography.labelLarge, - fontWeight = FontWeight.W700, - fontSize = 16.sp, - maxLines = 2 - ) - IconButton( - onClick = { requestAddBookToBookshelf(bookInformation.id) }, - modifier = Modifier.height(40.dp) - ) { - Icon( - painter = - if (!allBookshelfBookIds.contains(bookInformation.id)) - painterResource(R.drawable.outline_bookmark_24px) - else painterResource(R.drawable.filled_bookmark_24px), - contentDescription = "mark", - tint = MaterialTheme.colorScheme.onSurface - ) - } - } - Text( - text = stringResource( - id = R.string.book_info_detailed, - bookInformation.author, - bookInformation.publishingHouse, - bookInformation.lastUpdated.year, - bookInformation.lastUpdated.monthValue, - bookInformation.lastUpdated.dayOfMonth, - bookInformation.wordCount, - if (bookInformation.isComplete) stringResource(R.string.book_completed) - else stringResource(R.string.book_ongoing), - bookInformation.description.trim() - ), - style = MaterialTheme.typography.labelLarge, - fontSize = 13.sp, - lineHeight = 17.sp, - overflow = TextOverflow.Ellipsis - ) - } - } } \ No newline at end of file diff --git a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/expanded/ExpandedPageScreen.kt b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/expanded/ExpandedPageScreen.kt index c3019f0..942c57e 100644 --- a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/expanded/ExpandedPageScreen.kt +++ b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/expanded/ExpandedPageScreen.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -41,7 +42,8 @@ import androidx.lifecycle.compose.LifecycleEventEffect import indi.dmzz_yyhyy.lightnovelreader.R import indi.dmzz_yyhyy.lightnovelreader.ui.components.Component import indi.dmzz_yyhyy.lightnovelreader.ui.components.Loading -import indi.dmzz_yyhyy.lightnovelreader.ui.home.exploration.ExplorationBookCard +import indi.dmzz_yyhyy.lightnovelreader.ui.home.bookshelf.home.BookCardItem +import indi.dmzz_yyhyy.lightnovelreader.utils.withHaptic import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @@ -94,6 +96,7 @@ fun ExpandedPageScreen( modifier = Modifier .fillMaxSize() .nestedScroll(enterAlwaysScrollBehavior.nestedScrollConnection), + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 3.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { item { @@ -108,14 +111,12 @@ fun ExpandedPageScreen( Box(Modifier.height(3.dp)) } itemsIndexed(uiState.bookList) { index, bookInformation -> - ExplorationBookCard( - modifier = Modifier - .padding(start = 19.dp, end = 10.dp) - .animateItem(), + BookCardItem( bookInformation = bookInformation, - requestAddBookToBookshelf = requestAddBookToBookshelf, - allBookshelfBookIds = uiState.allBookshelfBookIds, - onClickBook = onClickBook + onClick = { onClickBook(bookInformation.id) }, + onLongPress = withHaptic {}, + collected = uiState.allBookshelfBookIds.contains(bookInformation.id), + progress = {}, ) LaunchedEffect(uiState.bookList.size) { if (uiState.bookList.size - index == 3) { @@ -137,7 +138,7 @@ fun TopBar( MediumTopAppBar( title = { Text( - text = "${stringResource(id = R.string.nav_exploration)} · $title", + text = stringResource(id = R.string.nav_exploration_child, title), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.W600, color = MaterialTheme.colorScheme.onSurface, diff --git a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/home/ExplorationHomeScreen.kt b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/home/ExplorationHomeScreen.kt index 380a7e3..fd31470 100644 --- a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/home/ExplorationHomeScreen.kt +++ b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/home/ExplorationHomeScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -18,6 +19,8 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -39,6 +42,7 @@ import androidx.compose.runtime.rememberCoroutineScope 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.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.painterResource @@ -185,23 +189,31 @@ fun ExplorationPage( modifier = Modifier.animateItem() ) { Row( - modifier = Modifier.fillMaxWidth().height(48.dp) - .padding(start = 16.dp), + modifier = Modifier + .padding(vertical = 4.dp) + .fillMaxWidth() + .height(46.dp) + .padding(start = 22.dp), verticalAlignment = Alignment.CenterVertically ) { Text( modifier = Modifier.weight(2f), text = explorationBooksRow.title, - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.W700, + fontSize = 17.sp, + fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onSurface ) if (explorationBooksRow.expandable) { - IconButton(onClick = { - explorationBooksRow.expandedPageDataSourceId?.let { - onClickExpand(it) + IconButton( + modifier = Modifier.size(40.dp) + .padding(end = 16.dp) + .padding(vertical = 6.dp), + onClick = { + explorationBooksRow.expandedPageDataSourceId?.let { + onClickExpand(it) + } } - }) { + ) { Icon( painter = painterResource(id = R.drawable.arrow_forward_24px), contentDescription = "expand" @@ -209,40 +221,80 @@ fun ExplorationPage( } } } + val lazyRowState = rememberLazyListState() + LazyRow( - modifier = Modifier.fillMaxWidth() - .padding(bottom = 11.dp, start = 8.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp) + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 12.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + state = lazyRowState, + flingBehavior = rememberSnapFlingBehavior(lazyRowState) ) { + item { + Box(modifier = Modifier.width(10.dp)) + } + items(explorationBooksRow.bookList) { explorationDisplayBook -> Column( - modifier = Modifier.clickable { - onClickBook(explorationDisplayBook.id) - } + modifier = Modifier + .clip(RoundedCornerShape(10.dp)) + .clickable { + onClickBook(explorationDisplayBook.id) + } ) { - Cover( - width = 88.dp, - height = 125.dp, - url = explorationDisplayBook.coverUrl - ) - Text( - modifier = Modifier.width(88.dp), - text = explorationDisplayBook.title, - style = MaterialTheme.typography.labelLarge, - fontWeight = FontWeight.W500, - fontSize = 12.sp, - lineHeight = 14.sp, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) + Box( + modifier = Modifier.padding(horizontal = 4.dp) + ) { + Cover( + width = 106.dp, + height = 162.dp, + url = explorationDisplayBook.coverUrl, + rounded = 10.dp + ) + } + Column( + modifier = Modifier + .width(108.dp) + .padding(horizontal = 2.dp) + .padding(top = 4.dp, bottom = 2.dp), + verticalArrangement = Arrangement.spacedBy(2.dp) + ) { + Text( + text = explorationDisplayBook.title, + fontWeight = FontWeight.Bold, + fontSize = 14.sp, + lineHeight = 18.sp, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + /* 可选作者(未实现) + Text( + text = explorationDisplayBook.author.toString(), + fontSize = 13.sp, + lineHeight = 18.sp, + color = MaterialTheme.colorScheme.secondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + */ + } } } + + item { + Box(modifier = Modifier.width(12.dp)) + } } - Box(Modifier.fillMaxWidth().padding(horizontal = 10.dp, vertical = 0.dp)) { + Box( + Modifier.fillMaxWidth() + .padding(horizontal = 16.dp) + ) { HorizontalDivider() } } } } + } } \ No newline at end of file diff --git a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/search/ExplorationSearchScreen.kt b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/search/ExplorationSearchScreen.kt index e7b4e54..19c55d1 100644 --- a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/search/ExplorationSearchScreen.kt +++ b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/ui/home/exploration/search/ExplorationSearchScreen.kt @@ -17,6 +17,8 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api @@ -36,6 +38,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.boundsInParent import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.res.painterResource @@ -53,14 +56,15 @@ import indi.dmzz_yyhyy.lightnovelreader.R import indi.dmzz_yyhyy.lightnovelreader.ui.components.AnimatedText import indi.dmzz_yyhyy.lightnovelreader.ui.components.EmptyPage import indi.dmzz_yyhyy.lightnovelreader.ui.components.Loading -import indi.dmzz_yyhyy.lightnovelreader.ui.home.exploration.ExplorationBookCard +import indi.dmzz_yyhyy.lightnovelreader.ui.home.bookshelf.home.BookCardItem +import indi.dmzz_yyhyy.lightnovelreader.utils.withHaptic @OptIn(ExperimentalMaterial3Api::class) @Composable fun ExplorationSearchScreen( topBar: (@Composable () -> Unit) -> Unit, requestAddBookToBookshelf: (Int) -> Unit, - onCLickBack: () -> Unit, + onClickBack: () -> Unit, init: () -> Unit, onChangeSearchType: (String) -> Unit, onSearch: (String) -> Unit, @@ -124,7 +128,7 @@ fun ExplorationSearchScreen( color = MaterialTheme.colorScheme.onSurfaceVariant, ) }, leadingIcon = { - IconButton(onClick = onCLickBack) { + IconButton(onClick = onClickBack) { Icon(painter = painterResource(R.drawable.arrow_back_24px), contentDescription = "back") } }, @@ -146,7 +150,7 @@ fun ExplorationSearchScreen( ) }, expanded = searchBarExpanded, - onExpandedChange = { if (!it) onCLickBack.invoke() } + onExpandedChange = { if (!it) onClickBack.invoke() } ) { AnimatedVisibility( visible = uiState.historyList.isEmpty() || uiState.historyList.all { it.isEmpty() }, @@ -164,46 +168,55 @@ fun ExplorationSearchScreen( enter = fadeIn(), exit = fadeOut() ) { - Column(Modifier.verticalScroll(rememberScrollState())) { + Column(Modifier + .padding(vertical = 8.dp) + .verticalScroll(rememberScrollState()) + ) { Row( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically, ) { Text( - modifier = Modifier.padding(16.dp, 8.dp), text = stringResource(id = R.string.search_history), - style = MaterialTheme.typography.displayLarge, fontSize = 16.sp, fontWeight = FontWeight.W700, lineHeight = 16.sp, - letterSpacing = 0.5.sp, - color = MaterialTheme.colorScheme.onSurfaceVariant ) + Box(Modifier.weight(2f)) - Text( - modifier = Modifier - .padding(16.dp, 8.dp) - .clickable(onClick = onClickClearAllHistory), - text = stringResource(id = R.string.search_history_clear), - style = MaterialTheme.typography.displayLarge, - fontSize = 16.sp, - fontWeight = FontWeight.W700, - lineHeight = 16.sp, - letterSpacing = 0.5.sp, - color = MaterialTheme.colorScheme.primary - ) + + Button( + onClick = onClickClearAllHistory, + colors = ButtonDefaults.buttonColors( + containerColor = Color.Transparent, + contentColor = MaterialTheme.colorScheme.primary + ), + elevation = ButtonDefaults.buttonElevation(0.dp) + ) { + Text( + text = stringResource(id = R.string.search_history_clear), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + lineHeight = 16.sp, + ) + } } + Box(Modifier.height(8.dp)) + uiState.historyList.forEach { history -> if (history.isEmpty()) return@forEach AnimatedContent( targetState = history, - label = "HistoryItemAnime" + label = "HistoryItemAnimation" ) { Row ( modifier = Modifier .fillMaxWidth() .height(46.dp) - .padding(horizontal = 16.dp ) + .padding(horizontal = 16.dp) .clickable { searchKeyword = it searchBarExpanded = false @@ -212,9 +225,9 @@ fun ExplorationSearchScreen( verticalAlignment = Alignment.CenterVertically ) { Text( + modifier = Modifier.padding(start = 8.dp), text = it, - style = MaterialTheme.typography.bodyLarge, - fontWeight = FontWeight.W400, + fontSize = 16.sp, color = MaterialTheme.colorScheme.onSurface ) Box(Modifier.weight(2f)) @@ -276,21 +289,22 @@ fun ExplorationSearchScreen( ) } items(uiState.searchResult) { - ExplorationBookCard( - modifier = Modifier.animateItem(), - allBookshelfBookIds = uiState.allBookshelfBookIds, + BookCardItem( bookInformation = it, - requestAddBookToBookshelf = requestAddBookToBookshelf, - onClickBook = onClickBook + onClick = { onClickBook(it.id) }, + onLongPress = withHaptic {}, + collected = uiState.allBookshelfBookIds.contains(it.id), + progress = {}, ) } - item {AnimatedVisibility( - visible = !uiState.isLoadingComplete, - enter = fadeIn(), - exit = fadeOut() - ) { + item { + AnimatedVisibility( + visible = !uiState.isLoadingComplete, + enter = fadeIn(), + exit = fadeOut() + ) { LinearProgressIndicator( - modifier = Modifier.fillMaxWidth().padding(8.dp), + modifier = Modifier.fillMaxWidth().padding(8.dp) ) } } diff --git a/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/utils/Haptic.kt b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/utils/Haptic.kt new file mode 100644 index 0000000..94a0373 --- /dev/null +++ b/app/src/main/kotlin/indi/dmzz_yyhyy/lightnovelreader/utils/Haptic.kt @@ -0,0 +1,16 @@ +package indi.dmzz_yyhyy.lightnovelreader.utils + +import androidx.compose.runtime.Composable +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalHapticFeedback + +@Composable +fun withHaptic(action: (() -> Unit)?): () -> Unit { + val haptic = LocalHapticFeedback.current + return { + action?.let { + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + it() + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 010657a..e625cd6 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -5,6 +5,7 @@ 书架 选择 书架 (%d) 探索 + 探索 · %s 首页 分类 设置 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ec23af..f8a30ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ Bookshelf Select Bookshelf (%d) Exploration + %s - Exploration Homepage Categories Settings