fix: 双击底栏书架滚动当前分组到顶,Pager 惯性传递移至 MainScreen

This commit is contained in:
HapeLee committed 2026-06-29 02:28:18 +08:00
1 parent e6f5e87613
commit 88152e0388
3 files changed
+48 -12

No files matched your search

@@ -10,6 +10,7 @@ import androidx.compose.animation.SharedTransitionScope
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -44,6 +45,7 @@ import androidx.compose.material3.rememberWideNavigationRailState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@@ -85,6 +87,7 @@ import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.navigation.AppNavigationBar import io.legado.app.ui.widget.components.navigation.AppNavigationBar
import io.legado.app.ui.widget.components.navigation.AppNavigationBarItem import io.legado.app.ui.widget.components.navigation.AppNavigationBarItem
import io.legado.app.ui.widget.components.pager.rememberPagerFlingPassThroughConnection
import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.text.AppText
import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.utils.sendToClip import io.legado.app.utils.sendToClip
@@ -189,6 +192,11 @@ fun MainScreen(
if (index != -1) index else 0 if (index != -1) index else 0
} }
val pagerState = rememberPagerState(initialPage = initialPage) { destinations.size } val pagerState = rememberPagerState(initialPage = initialPage) { destinations.size }
val pagerNestedScrollConnection = rememberPagerFlingPassThroughConnection(
state = pagerState,
orientation = Orientation.Horizontal,
)
var bookshelfScrollToTopRequest by remember { mutableLongStateOf(0L) }
LaunchedEffect(destinations) { LaunchedEffect(destinations) {
if (destinations.isNotEmpty() && pagerState.currentPage !in destinations.indices) { if (destinations.isNotEmpty() && pagerState.currentPage !in destinations.indices) {
pagerState.scrollToPage(destinations.lastIndex) pagerState.scrollToPage(destinations.lastIndex)
@@ -366,6 +374,7 @@ fun MainScreen(
) { ) {
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
pageNestedScrollConnection = pagerNestedScrollConnection,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.then( .then(
@@ -388,6 +397,7 @@ fun MainScreen(
) )
MainDestination.Bookshelf -> BookshelfScreen( MainDestination.Bookshelf -> BookshelfScreen(
scrollToTopRequest = bookshelfScrollToTopRequest,
onBookClick = { book -> onBookClick = { book ->
context.startActivityForBook(book) context.startActivityForBook(book)
}, },
@@ -493,6 +503,16 @@ fun MainScreen(
pagerState.animateScrollToPage(index) pagerState.animateScrollToPage(index)
} }
}, },
onDoubleClick = if (destination == MainDestination.Bookshelf) {
{
bookshelfScrollToTopRequest++
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
}
} else {
null
},
modifier = Modifier modifier = Modifier
.defaultMinSize(minWidth = 76.dp) .defaultMinSize(minWidth = 76.dp)
.semantics(mergeDescendants = true) { .semantics(mergeDescendants = true) {
@@ -27,7 +27,6 @@ import androidx.compose.animation.scaleOut
import androidx.compose.animation.shrinkVertically import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.togetherWith import androidx.compose.animation.togetherWith
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -131,7 +130,6 @@ import io.legado.app.ui.widget.components.list.TopFloatingStickyItem
import io.legado.app.ui.widget.components.log.AppLogSheet import io.legado.app.ui.widget.components.log.AppLogSheet
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.pager.rememberPagerFlingPassThroughConnection
import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
import io.legado.app.ui.widget.components.tabRow.AppTabRow import io.legado.app.ui.widget.components.tabRow.AppTabRow
import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.text.AppText
@@ -157,6 +155,7 @@ import sh.calvin.reorderable.rememberReorderableLazyGridState
@Composable @Composable
fun BookshelfScreen( fun BookshelfScreen(
viewModel: BookshelfViewModel = koinViewModel(), viewModel: BookshelfViewModel = koinViewModel(),
scrollToTopRequest: Long = 0L,
onBookClick: (BookShelfItem) -> Unit, onBookClick: (BookShelfItem) -> Unit,
onBookLongClick: (book: BookShelfItem, sharedCoverKey: String?) -> Unit, onBookLongClick: (book: BookShelfItem, sharedCoverKey: String?) -> Unit,
onNavigateToSearch: (String) -> Unit, onNavigateToSearch: (String) -> Unit,
@@ -234,10 +233,6 @@ fun BookshelfScreen(
initialPage = uiState.selectedGroupIndex.coerceAtLeast(0), initialPage = uiState.selectedGroupIndex.coerceAtLeast(0),
pageCount = { uiState.groups.size } pageCount = { uiState.groups.size }
) )
val childPagerNestedScrollConnection = rememberPagerFlingPassThroughConnection(
state = pagerState,
orientation = Orientation.Horizontal,
)
val latestGroups by rememberUpdatedState(uiState.groups) val latestGroups by rememberUpdatedState(uiState.groups)
val latestSelectedGroupId by rememberUpdatedState(uiState.selectedGroupId) val latestSelectedGroupId by rememberUpdatedState(uiState.selectedGroupId)
@@ -819,6 +814,7 @@ fun BookshelfScreen(
} else { } else {
if (isUsingStandaloneSearchGroup) { if (isUsingStandaloneSearchGroup) {
BookshelfPage( BookshelfPage(
scrollToTopRequest = scrollToTopRequest,
paddingValues = paddingValues, paddingValues = paddingValues,
books = uiState.items, books = uiState.items,
uiState = uiState, uiState = uiState,
@@ -840,7 +836,6 @@ fun BookshelfScreen(
} else { } else {
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
pageNestedScrollConnection = childPagerNestedScrollConnection,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.then( .then(
@@ -866,6 +861,7 @@ fun BookshelfScreen(
?: uiState.bookshelfSort) == 3 && ?: uiState.bookshelfSort) == 3 &&
isSelectedGroup isSelectedGroup
BookshelfPage( BookshelfPage(
scrollToTopRequest = scrollToTopRequest,
paddingValues = paddingValues, paddingValues = paddingValues,
books = books, books = books,
uiState = uiState, uiState = uiState,
@@ -1215,6 +1211,7 @@ private data class BookshelfEditStickySummary(
@Composable @Composable
fun BookshelfPage( fun BookshelfPage(
scrollToTopRequest: Long,
paddingValues: PaddingValues, paddingValues: PaddingValues,
books: ImmutableList<BookUiItem>, books: ImmutableList<BookUiItem>,
uiState: BookshelfUiState, uiState: BookshelfUiState,
@@ -1301,6 +1298,11 @@ fun BookshelfPage(
val hapticFeedback = LocalHapticFeedback.current val hapticFeedback = LocalHapticFeedback.current
val displayBooks = draggingBooks ?: pendingSavedBooks ?: books val displayBooks = draggingBooks ?: pendingSavedBooks ?: books
val gridState = rememberLazyGridState() val gridState = rememberLazyGridState()
LaunchedEffect(scrollToTopRequest, isCurrentPage) {
if (scrollToTopRequest > 0L && isCurrentPage) {
gridState.animateScrollToItem(0)
}
}
val reorderableState = rememberReorderableLazyGridState(gridState) { from, to -> val reorderableState = rememberReorderableLazyGridState(gridState) { from, to ->
if (canReorderBooks) { if (canReorderBooks) {
onMoveBook(from.index, to.index, displayBooks) onMoveBook(from.index, to.index, displayBooks)
@@ -9,6 +9,7 @@ import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.EaseOut import androidx.compose.animation.core.EaseOut
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@@ -77,6 +78,7 @@ val LocalFloatingBottomBarTabScale = staticCompositionLocalOf { { 1f } }
@Composable @Composable
fun RowScope.FloatingBottomBarItem( fun RowScope.FloatingBottomBarItem(
onClick: () -> Unit, onClick: () -> Unit,
onDoubleClick: (() -> Unit)? = null,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit content: @Composable ColumnScope.() -> Unit
) { ) {
@@ -84,11 +86,23 @@ fun RowScope.FloatingBottomBarItem(
Column( Column(
modifier modifier
.clip(ContinuousCapsule) .clip(ContinuousCapsule)
.clickable( .then(
interactionSource = null, if (onDoubleClick != null) {
indication = null, Modifier.combinedClickable(
role = Role.Tab, interactionSource = null,
onClick = onClick indication = null,
role = Role.Tab,
onClick = onClick,
onDoubleClick = onDoubleClick,
)
} else {
Modifier.clickable(
interactionSource = null,
indication = null,
role = Role.Tab,
onClick = onClick,
)
}
) )
.fillMaxHeight() .fillMaxHeight()
.weight(1f) .weight(1f)