优化文件夹与书架切换时的动画与跟随手势
This commit is contained in:
@@ -5,18 +5,29 @@ import android.content.res.Configuration
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||||
|
import androidx.activity.compose.PredictiveBackHandler
|
||||||
import androidx.activity.compose.ReportDrawnWhen
|
import androidx.activity.compose.ReportDrawnWhen
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.AnimatedVisibilityScope
|
import androidx.compose.animation.AnimatedVisibilityScope
|
||||||
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.slideInVertically
|
import androidx.compose.animation.slideInVertically
|
||||||
import androidx.compose.animation.slideOutVertically
|
import androidx.compose.animation.slideOutVertically
|
||||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||||
import androidx.compose.animation.SharedTransitionScope
|
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.clickable
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
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.group.GroupEditSheet
|
||||||
import io.legado.app.ui.book.info.GroupSelectSheet
|
import io.legado.app.ui.book.info.GroupSelectSheet
|
||||||
import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
|
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.main.bookCoverSharedElementKey
|
||||||
import io.legado.app.ui.theme.LegadoTheme
|
import io.legado.app.ui.theme.LegadoTheme
|
||||||
import io.legado.app.ui.theme.ThemeResolver
|
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.ImmutableList
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
@@ -141,7 +154,8 @@ import sh.calvin.reorderable.rememberReorderableLazyGridState
|
|||||||
|
|
||||||
@OptIn(
|
@OptIn(
|
||||||
ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
|
ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
|
||||||
ExperimentalMaterial3ExpressiveApi::class, ExperimentalSharedTransitionApi::class
|
ExperimentalMaterial3ExpressiveApi::class, ExperimentalSharedTransitionApi::class,
|
||||||
|
ExperimentalAnimationApi::class
|
||||||
)
|
)
|
||||||
@Composable
|
@Composable
|
||||||
fun BookshelfScreen(
|
fun BookshelfScreen(
|
||||||
@@ -167,6 +181,13 @@ fun BookshelfScreen(
|
|||||||
val isInFolderRoot = uiState.isInFolderRoot
|
val isInFolderRoot = uiState.isInFolderRoot
|
||||||
val bookGroupStyle = uiState.bookGroupStyle
|
val bookGroupStyle = uiState.bookGroupStyle
|
||||||
|
|
||||||
|
val transitionState = remember { SeekableTransitionState(isInFolderRoot) }
|
||||||
|
LaunchedEffect(isInFolderRoot) {
|
||||||
|
if (transitionState.targetState != isInFolderRoot) {
|
||||||
|
transitionState.animateTo(isInFolderRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val clipboardManager = LocalClipboard.current
|
val clipboardManager = LocalClipboard.current
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
|
||||||
@@ -327,9 +348,15 @@ fun BookshelfScreen(
|
|||||||
|
|
||||||
val currentGroupName by remember { derivedStateOf { uiState.currentGroupName } }
|
val currentGroupName by remember { derivedStateOf { uiState.currentGroupName } }
|
||||||
|
|
||||||
if (bookGroupStyle == 2 && !isInFolderRoot && !isEditMode) {
|
PredictiveBackHandler(enabled = bookGroupStyle == 2 && !isInFolderRoot && !isEditMode) { progress ->
|
||||||
BackHandler {
|
try {
|
||||||
|
progress.collect { backEvent ->
|
||||||
|
transitionState.seekTo(backEvent.progress, targetState = true)
|
||||||
|
}
|
||||||
viewModel.setInFolderRoot(true)
|
viewModel.setInFolderRoot(true)
|
||||||
|
transitionState.animateTo(true)
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
transitionState.animateTo(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,9 +747,26 @@ fun BookshelfScreen(
|
|||||||
enabled = pullToRefreshEnabled
|
enabled = pullToRefreshEnabled
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
AnimatedContent(
|
val transition = rememberTransition(
|
||||||
targetState = isInFolderRoot,
|
transitionState,
|
||||||
label = "FolderTransition"
|
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 ->
|
) { isRoot ->
|
||||||
if (bookGroupStyle == 2 && isRoot && !isUsingStandaloneSearchGroup) {
|
if (bookGroupStyle == 2 && isRoot && !isUsingStandaloneSearchGroup) {
|
||||||
val folderColumns =
|
val folderColumns =
|
||||||
@@ -739,7 +783,7 @@ fun BookshelfScreen(
|
|||||||
),
|
),
|
||||||
contentPadding = adaptiveContentPaddingBookshelf(
|
contentPadding = adaptiveContentPaddingBookshelf(
|
||||||
top = paddingValues.calculateTopPadding(),
|
top = paddingValues.calculateTopPadding(),
|
||||||
bottom = 120.dp,
|
bottom = if (ThemeConfig.useFloatingBottomBar) 120.dp else 8.dp,
|
||||||
horizontal = if (isGridMode) 8.dp else 4.dp
|
horizontal = if (isGridMode) 8.dp else 4.dp
|
||||||
),
|
),
|
||||||
verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
|
verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
|
||||||
@@ -830,7 +874,7 @@ fun BookshelfScreen(
|
|||||||
if (this != null) Modifier.skipToLookaheadSize() else Modifier
|
if (this != null) Modifier.skipToLookaheadSize() else Modifier
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
beyondViewportPageCount = 2,
|
beyondViewportPageCount = 1,
|
||||||
key = { if (it < uiState.groups.size) uiState.groups[it].groupId else it }
|
key = { if (it < uiState.groups.size) uiState.groups[it].groupId else it }
|
||||||
) { pageIndex ->
|
) { pageIndex ->
|
||||||
val group = uiState.groups.getOrNull(pageIndex)
|
val group = uiState.groups.getOrNull(pageIndex)
|
||||||
@@ -1310,7 +1354,7 @@ fun BookshelfPage(
|
|||||||
),
|
),
|
||||||
contentPadding = adaptiveContentPaddingBookshelf(
|
contentPadding = adaptiveContentPaddingBookshelf(
|
||||||
top = paddingValues.calculateTopPadding(),
|
top = paddingValues.calculateTopPadding(),
|
||||||
bottom = 120.dp,
|
bottom = if (ThemeConfig.useFloatingBottomBar) 120.dp else 8.dp,
|
||||||
horizontal = if (isGridMode) 8.dp else 4.dp
|
horizontal = if (isGridMode) 8.dp else 4.dp
|
||||||
),
|
),
|
||||||
verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
|
verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
|
||||||
|
|||||||
Reference in New Issue
Block a user