From 764388a937b2fb1b0f56016004b81be18c09704f Mon Sep 17 00:00:00 2001 From: Gabriel Souza Date: Tue, 21 May 2024 08:32:02 -0300 Subject: [PATCH] Per screen transition experimental api (#424) * Per Screen transition experimental API * Update transitionSpec to avoid behavior change * fix lint * update api dump --- .../api/android/voyager-transitions.api | 5 ++ .../api/desktop/voyager-transitions.api | 5 ++ .../voyager/transitions/ScreenTransition.kt | 47 ++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/voyager-transitions/api/android/voyager-transitions.api b/voyager-transitions/api/android/voyager-transitions.api index b43c5911..ec515e72 100644 --- a/voyager-transitions/api/android/voyager-transitions.api +++ b/voyager-transitions/api/android/voyager-transitions.api @@ -47,6 +47,11 @@ public final class cafe/adriel/voyager/transitions/ScaleTransitionKt { public static final fun ScaleTransition (Lcafe/adriel/voyager/navigator/Navigator;Landroidx/compose/ui/Modifier;Landroidx/compose/animation/core/FiniteAnimationSpec;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V } +public final class cafe/adriel/voyager/transitions/ScreenTransition$DefaultImpls { + public static fun enter (Lcafe/adriel/voyager/transitions/ScreenTransition;)Landroidx/compose/animation/EnterTransition; + public static fun exit (Lcafe/adriel/voyager/transitions/ScreenTransition;)Landroidx/compose/animation/ExitTransition; +} + public final class cafe/adriel/voyager/transitions/ScreenTransitionKt { public static final fun ScreenTransition (Lcafe/adriel/voyager/navigator/Navigator;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V public static final fun ScreenTransition (Lcafe/adriel/voyager/navigator/Navigator;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V diff --git a/voyager-transitions/api/desktop/voyager-transitions.api b/voyager-transitions/api/desktop/voyager-transitions.api index f384847d..a0e74a56 100644 --- a/voyager-transitions/api/desktop/voyager-transitions.api +++ b/voyager-transitions/api/desktop/voyager-transitions.api @@ -47,6 +47,11 @@ public final class cafe/adriel/voyager/transitions/ScaleTransitionKt { public static final fun ScaleTransition (Lcafe/adriel/voyager/navigator/Navigator;Landroidx/compose/ui/Modifier;Landroidx/compose/animation/core/FiniteAnimationSpec;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V } +public final class cafe/adriel/voyager/transitions/ScreenTransition$DefaultImpls { + public static fun enter (Lcafe/adriel/voyager/transitions/ScreenTransition;)Landroidx/compose/animation/EnterTransition; + public static fun exit (Lcafe/adriel/voyager/transitions/ScreenTransition;)Landroidx/compose/animation/ExitTransition; +} + public final class cafe/adriel/voyager/transitions/ScreenTransitionKt { public static final fun ScreenTransition (Lcafe/adriel/voyager/navigator/Navigator;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V public static final fun ScreenTransition (Lcafe/adriel/voyager/navigator/Navigator;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V diff --git a/voyager-transitions/src/commonMain/kotlin/cafe/adriel/voyager/transitions/ScreenTransition.kt b/voyager-transitions/src/commonMain/kotlin/cafe/adriel/voyager/transitions/ScreenTransition.kt index c09bb2d8..e0b1fb3d 100644 --- a/voyager-transitions/src/commonMain/kotlin/cafe/adriel/voyager/transitions/ScreenTransition.kt +++ b/voyager-transitions/src/commonMain/kotlin/cafe/adriel/voyager/transitions/ScreenTransition.kt @@ -4,12 +4,34 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.ContentTransform +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.togetherWith import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import cafe.adriel.voyager.core.annotation.ExperimentalVoyagerApi import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.stack.StackEvent import cafe.adriel.voyager.navigator.Navigator +@ExperimentalVoyagerApi +public interface ScreenTransition { + + /** + * Defines the enter transition for the Screen. + * + * Returns null when it should not define a transition for this screen. + */ + public fun enter(): EnterTransition? = null + + /** + * Defines the exit transition for the Screen. + * + * Returns null when it should not define a transition for this screen. + */ + public fun exit(): ExitTransition? = null +} + public typealias ScreenTransitionContent = @Composable AnimatedVisibilityScope.(Screen) -> Unit @Composable @@ -42,7 +64,30 @@ public fun ScreenTransition( ) { AnimatedContent( targetState = navigator.lastItem, - transitionSpec = transition, + transitionSpec = { + val contentTransform = transition() + + val isPop = navigator.lastEvent == StackEvent.Pop + + val screenEnterTransition = if (isPop) { + (targetState as? ScreenTransition)?.enter() + } else { + (targetState as? ScreenTransition)?.enter() + } + + val screenExitTransition = if (isPop) { + (initialState as? ScreenTransition)?.exit() + } else { + (initialState as? ScreenTransition)?.exit() + } + + if (screenExitTransition != null || screenEnterTransition != null) { + (screenEnterTransition ?: contentTransform.targetContentEnter) togetherWith + (screenExitTransition ?: contentTransform.initialContentExit) + } else { + contentTransform + } + }, modifier = modifier ) { screen -> navigator.saveableState("transition", screen) {