From 56d82d5e256e2a1254d943faf5be6aaaa36cac16 Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Thu, 14 May 2026 20:07:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6=E5=A4=B9?= =?UTF-8?q?=E4=B8=8E=E4=B9=A6=E6=9E=B6=E5=88=87=E6=8D=A2=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E4=B8=8E=E8=B7=9F=E9=9A=8F=E6=89=8B=E5=8A=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/ui/main/bookshelf/BookshelfScreen.kt | 60 ++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) 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 4ae70311a..146361064 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 @@ -5,18 +5,29 @@ import android.content.res.Configuration import android.net.Uri import androidx.activity.compose.BackHandler import androidx.activity.compose.ManagedActivityResultLauncher +import androidx.activity.compose.PredictiveBackHandler import androidx.activity.compose.ReportDrawnWhen import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.SharedTransitionScope +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.SeekableTransitionState +import androidx.compose.animation.core.rememberTransition +import androidx.compose.animation.core.tween +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.togetherWith import androidx.compose.foundation.clickable import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement @@ -101,6 +112,7 @@ import io.legado.app.data.entities.BookGroup import io.legado.app.ui.book.group.GroupEditSheet import io.legado.app.ui.book.info.GroupSelectSheet import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig +import io.legado.app.ui.config.themeConfig.ThemeConfig import io.legado.app.ui.main.bookCoverSharedElementKey import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver @@ -133,6 +145,7 @@ import io.legado.app.ui.widget.components.text.AppText import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -141,7 +154,8 @@ import sh.calvin.reorderable.rememberReorderableLazyGridState @OptIn( ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class, - ExperimentalMaterial3ExpressiveApi::class, ExperimentalSharedTransitionApi::class + ExperimentalMaterial3ExpressiveApi::class, ExperimentalSharedTransitionApi::class, + ExperimentalAnimationApi::class ) @Composable fun BookshelfScreen( @@ -167,6 +181,13 @@ fun BookshelfScreen( val isInFolderRoot = uiState.isInFolderRoot val bookGroupStyle = uiState.bookGroupStyle + val transitionState = remember { SeekableTransitionState(isInFolderRoot) } + LaunchedEffect(isInFolderRoot) { + if (transitionState.targetState != isInFolderRoot) { + transitionState.animateTo(isInFolderRoot) + } + } + val clipboardManager = LocalClipboard.current val snackbarHostState = remember { SnackbarHostState() } @@ -327,9 +348,15 @@ fun BookshelfScreen( val currentGroupName by remember { derivedStateOf { uiState.currentGroupName } } - if (bookGroupStyle == 2 && !isInFolderRoot && !isEditMode) { - BackHandler { + PredictiveBackHandler(enabled = bookGroupStyle == 2 && !isInFolderRoot && !isEditMode) { progress -> + try { + progress.collect { backEvent -> + transitionState.seekTo(backEvent.progress, targetState = true) + } viewModel.setInFolderRoot(true) + transitionState.animateTo(true) + } catch (e: CancellationException) { + transitionState.animateTo(false) } } @@ -720,9 +747,26 @@ fun BookshelfScreen( enabled = pullToRefreshEnabled ) ) { - AnimatedContent( - targetState = isInFolderRoot, + val transition = rememberTransition( + transitionState, label = "FolderTransition" + ) + transition.AnimatedContent( + transitionSpec = { + val easing = FastOutSlowInEasing + val duration = 480 + if (targetState) { + (fadeIn(animationSpec = tween(duration, easing = easing)) + + scaleIn(initialScale = 1.05f, animationSpec = tween(duration, easing = easing))) + .togetherWith(fadeOut(animationSpec = tween(duration, easing = easing)) + + scaleOut(targetScale = 0.95f, animationSpec = tween(duration, easing = easing))) + } else { + (fadeIn(animationSpec = tween(duration, easing = easing)) + + scaleIn(initialScale = 0.95f, animationSpec = tween(duration, easing = easing))) + .togetherWith(fadeOut(animationSpec = tween(duration, easing = easing)) + + scaleOut(targetScale = 1.05f, animationSpec = tween(duration, easing = easing))) + } + } ) { isRoot -> if (bookGroupStyle == 2 && isRoot && !isUsingStandaloneSearchGroup) { val folderColumns = @@ -739,7 +783,7 @@ fun BookshelfScreen( ), contentPadding = adaptiveContentPaddingBookshelf( top = paddingValues.calculateTopPadding(), - bottom = 120.dp, + bottom = if (ThemeConfig.useFloatingBottomBar) 120.dp else 8.dp, horizontal = if (isGridMode) 8.dp else 4.dp ), verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp), @@ -830,7 +874,7 @@ fun BookshelfScreen( if (this != null) Modifier.skipToLookaheadSize() else Modifier } ), - beyondViewportPageCount = 2, + beyondViewportPageCount = 1, key = { if (it < uiState.groups.size) uiState.groups[it].groupId else it } ) { pageIndex -> val group = uiState.groups.getOrNull(pageIndex) @@ -1310,7 +1354,7 @@ fun BookshelfPage( ), contentPadding = adaptiveContentPaddingBookshelf( top = paddingValues.calculateTopPadding(), - bottom = 120.dp, + bottom = if (ThemeConfig.useFloatingBottomBar) 120.dp else 8.dp, horizontal = if (isGridMode) 8.dp else 4.dp ), verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),