Improve screen transitions

This commit is contained in:
vfsfitvnm 2022-09-29 18:01:32 +02:00
parent 6f222ac564
commit 982a7eaca7
4 changed files with 69 additions and 18 deletions

View file

@ -3,6 +3,8 @@ package it.vfsfitvnm.vimusic.ui.components.themed
import android.content.Intent import android.content.Intent
import android.text.format.DateUtils import android.text.format.DateUtils
import androidx.compose.animation.AnimatedContentScope import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.with import androidx.compose.animation.with
import androidx.compose.foundation.background import androidx.compose.foundation.background
@ -35,7 +37,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import it.vfsfitvnm.route.RouteHandler import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.route.empty
import it.vfsfitvnm.vimusic.Database import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.R
@ -282,7 +283,7 @@ fun MediaItemMenu(
else -> when (initialState.route) { else -> when (initialState.route) {
viewPlaylistsRoute -> slideIntoContainer(AnimatedContentScope.SlideDirection.Right) with viewPlaylistsRoute -> slideIntoContainer(AnimatedContentScope.SlideDirection.Right) with
slideOutOfContainer(AnimatedContentScope.SlideDirection.Right) slideOutOfContainer(AnimatedContentScope.SlideDirection.Right)
else -> empty else -> EnterTransition.None with ExitTransition.None
} }
} }
} }

View file

@ -5,6 +5,12 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.saveable.rememberSaveableStateHolder import androidx.compose.runtime.saveable.rememberSaveableStateHolder
import it.vfsfitvnm.route.RouteHandler import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.route.defaultStacking
import it.vfsfitvnm.route.defaultStill
import it.vfsfitvnm.route.defaultUnstacking
import it.vfsfitvnm.route.isStacking
import it.vfsfitvnm.route.isUnknown
import it.vfsfitvnm.route.isUnstacking
import it.vfsfitvnm.vimusic.Database import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.models.SearchQuery import it.vfsfitvnm.vimusic.models.SearchQuery
@ -33,7 +39,21 @@ import it.vfsfitvnm.vimusic.utils.rememberPreference
fun HomeScreen(onPlaylistUrl: (String) -> Unit) { fun HomeScreen(onPlaylistUrl: (String) -> Unit) {
val saveableStateHolder = rememberSaveableStateHolder() val saveableStateHolder = rememberSaveableStateHolder()
RouteHandler(listenToGlobalEmitter = true) { RouteHandler(
listenToGlobalEmitter = true,
transitionSpec = {
when {
isStacking -> defaultStacking
isUnstacking -> defaultUnstacking
isUnknown -> when {
initialState.route == searchRoute && targetState.route == searchResultRoute -> defaultStacking
initialState.route == searchResultRoute && targetState.route == searchRoute -> defaultUnstacking
else -> defaultStill
}
else -> defaultStill
}
}
) {
globalRoutes() globalRoutes()
settingsRoute { settingsRoute {
@ -65,6 +85,7 @@ fun HomeScreen(onPlaylistUrl: (String) -> Unit) {
SearchScreen( SearchScreen(
initialTextInput = initialTextInput, initialTextInput = initialTextInput,
onSearch = { query -> onSearch = { query ->
pop()
searchResultRoute(query) searchResultRoute(query)
query { query {

View file

@ -21,7 +21,13 @@ fun RouteHandler(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
listenToGlobalEmitter: Boolean = false, listenToGlobalEmitter: Boolean = false,
handleBackPress: Boolean = true, handleBackPress: Boolean = true,
transitionSpec: AnimatedContentScope<RouteHandlerScope>.() -> ContentTransform = { fastFade }, transitionSpec: AnimatedContentScope<RouteHandlerScope>.() -> ContentTransform = {
when {
isStacking -> defaultStacking
isStill -> defaultStill
else -> defaultUnstacking
}
},
content: @Composable RouteHandlerScope.() -> Unit content: @Composable RouteHandlerScope.() -> Unit
) { ) {
var route by rememberSaveable(stateSaver = Route.Saver) { var route by rememberSaveable(stateSaver = Route.Saver) {
@ -47,7 +53,13 @@ fun RouteHandler(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
listenToGlobalEmitter: Boolean = false, listenToGlobalEmitter: Boolean = false,
handleBackPress: Boolean = true, handleBackPress: Boolean = true,
transitionSpec: AnimatedContentScope<RouteHandlerScope>.() -> ContentTransform = { fastFade }, transitionSpec: AnimatedContentScope<RouteHandlerScope>.() -> ContentTransform = {
when {
isStacking -> defaultStacking
isStill -> defaultStill
else -> defaultUnstacking
}
},
content: @Composable RouteHandlerScope.() -> Unit content: @Composable RouteHandlerScope.() -> Unit
) { ) {
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher

View file

@ -3,27 +3,44 @@ package it.vfsfitvnm.route
import androidx.compose.animation.AnimatedContentScope import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.ContentTransform import androidx.compose.animation.ContentTransform
import androidx.compose.animation.EnterTransition import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.with import androidx.compose.animation.scaleOut
@ExperimentalAnimationApi @ExperimentalAnimationApi
val AnimatedContentScope<RouteHandlerScope>.leftSlide: ContentTransform val defaultStacking = ContentTransform(
get() = slideIntoContainer(AnimatedContentScope.SlideDirection.Left) with initialContentExit = scaleOut(targetScale = 0.9f) + fadeOut(),
slideOutOfContainer(AnimatedContentScope.SlideDirection.Left) targetContentEnter = fadeIn(),
targetContentZIndex = 1f
)
@ExperimentalAnimationApi @ExperimentalAnimationApi
val AnimatedContentScope<RouteHandlerScope>.rightSlide: ContentTransform val defaultUnstacking = ContentTransform(
get() = slideIntoContainer(AnimatedContentScope.SlideDirection.Right) with initialContentExit = fadeOut(),
slideOutOfContainer(AnimatedContentScope.SlideDirection.Right) targetContentEnter = EnterTransition.None,
targetContentZIndex = 0f
)
@ExperimentalAnimationApi @ExperimentalAnimationApi
val AnimatedContentScope<RouteHandlerScope>.fastFade: ContentTransform val defaultStill = ContentTransform(
get() = fadeIn(tween(200)) with fadeOut(tween(200)) initialContentExit = scaleOut(targetScale = 0.9f) + fadeOut(),
targetContentEnter = fadeIn(),
targetContentZIndex = 1f
)
@ExperimentalAnimationApi @ExperimentalAnimationApi
val AnimatedContentScope<RouteHandlerScope>.empty: ContentTransform inline val AnimatedContentScope<RouteHandlerScope>.isStacking: Boolean
get() = EnterTransition.None with ExitTransition.None get() = initialState.route == null && targetState.route != null
@ExperimentalAnimationApi
inline val AnimatedContentScope<RouteHandlerScope>.isUnstacking: Boolean
get() = initialState.route != null && targetState.route == null
@ExperimentalAnimationApi
inline val AnimatedContentScope<RouteHandlerScope>.isStill: Boolean
get() = initialState.route == null && targetState.route == null
@ExperimentalAnimationApi
inline val AnimatedContentScope<RouteHandlerScope>.isUnknown: Boolean
get() = initialState.route != null && targetState.route != null