Skip to content

Commit

Permalink
Make scene provide an AnimatedContentScope to the composable content
Browse files Browse the repository at this point in the history
This scope is the one that drives the navigation transition, which
allows callers to use it to drive other animations inside the screen
itself as it animates into or out of the NavHost.
Notably, this allows callers to use the shared element transitions.
  • Loading branch information
StylianosGakis committed Apr 17, 2024
1 parent 0db393c commit 2c4d92d
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package moe.tlaster.precompose.navigation

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.core.ExperimentalTransitionApi
Expand Down Expand Up @@ -258,7 +259,7 @@ fun NavHost(
}

@Composable
private fun NavHostContent(
private fun AnimatedContentScope.NavHostContent(
stateHolder: SaveableStateHolder,
entry: BackStackEntry,
) {
Expand All @@ -268,7 +269,7 @@ private fun NavHostContent(
LocalSavedStateHolder provides entry.savedStateHolder,
LocalLifecycleOwner provides entry,
content = {
entry.ComposeContent()
entry.ComposeContent(this@NavHostContent)
},
)
}
Expand All @@ -289,12 +290,12 @@ private fun GroupRoute.composeRoute(): ComposeRoute? {
}

@Composable
private fun BackStackEntry.ComposeContent() {
private fun BackStackEntry.ComposeContent(animatedContentScope: AnimatedContentScope) {
if (route is GroupRoute) {
(route as GroupRoute).composeRoute()
} else {
route as? ComposeRoute
}?.content?.invoke(this)
}?.content?.invoke(animatedContentScope, this)
}

@OptIn(ExperimentalFoundationApi::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package moe.tlaster.precompose.navigation

import androidx.compose.animation.AnimatedContentScope
import androidx.compose.runtime.Composable
import moe.tlaster.precompose.navigation.route.FloatingRoute
import moe.tlaster.precompose.navigation.route.GroupRoute
import moe.tlaster.precompose.navigation.route.Route
import moe.tlaster.precompose.navigation.route.SceneRoute
import moe.tlaster.precompose.navigation.route.sceneRouteWithoutAnimatedContent
import moe.tlaster.precompose.navigation.transition.NavTransition

class RouteBuilder(
Expand All @@ -19,12 +21,43 @@ class RouteBuilder(
* @param swipeProperties swipe back navigation properties for current scene
* @param content composable for the destination
*/
@Deprecated(
message = "Deprecated in favor of scene that supports AnimatedContent",
level = DeprecationLevel.HIDDEN,
)
fun scene(
route: String,
deepLinks: List<String> = emptyList(),
navTransition: NavTransition? = null,
swipeProperties: SwipeProperties? = null,
content: @Composable (BackStackEntry) -> Unit,
) {
addRoute(
@Suppress("DEPRECATION")
sceneRouteWithoutAnimatedContent(
route = route,
navTransition = navTransition,
deepLinks = deepLinks,
swipeProperties = swipeProperties,
content = content,
),
)
}

/**
* Add the scene [Composable] to the [RouteBuilder]
* @param route route for the destination
* @param navTransition navigation transition for current scene
* @param swipeProperties swipe back navigation properties for current scene
* @param content composable for the destination. The AnimatedContentScope provided is the
* animation that drives the scene transition. That is either entering or exiting the NavHost
*/
fun scene(
route: String,
deepLinks: List<String> = emptyList(),
navTransition: NavTransition? = null,
swipeProperties: SwipeProperties? = null,
content: @Composable AnimatedContentScope.(BackStackEntry) -> Unit,
) {
addRoute(
SceneRoute(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package moe.tlaster.precompose.navigation.route

import androidx.compose.animation.AnimatedContentScope
import androidx.compose.runtime.Composable
import moe.tlaster.precompose.navigation.BackStackEntry

interface ComposeRoute : Route {
val content: @Composable (BackStackEntry) -> Unit
val content: @Composable AnimatedContentScope.(BackStackEntry) -> Unit
}

interface ComposeSceneRoute : ComposeRoute
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
package moe.tlaster.precompose.navigation.route

import androidx.compose.animation.AnimatedContentScope
import androidx.compose.runtime.Composable
import moe.tlaster.precompose.navigation.BackStackEntry

internal class FloatingRoute(
override val content: @Composable (BackStackEntry) -> Unit,
override val content: @Composable AnimatedContentScope.(BackStackEntry) -> Unit,
override val route: String,
) : ComposeRoute, ComposeFloatingRoute
) : ComposeRoute, ComposeFloatingRoute {
internal constructor(
route: String,
content: @Composable (BackStackEntry) -> Unit
) : this(
{ entry -> content(entry) },
route,
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package moe.tlaster.precompose.navigation.route

import androidx.compose.animation.AnimatedContentScope
import androidx.compose.runtime.Composable
import moe.tlaster.precompose.navigation.BackStackEntry
import moe.tlaster.precompose.navigation.SwipeProperties
Expand All @@ -10,5 +11,28 @@ internal class SceneRoute(
val deepLinks: List<String>,
val navTransition: NavTransition?,
val swipeProperties: SwipeProperties?,
override val content: @Composable (BackStackEntry) -> Unit,
override val content: @Composable AnimatedContentScope.(BackStackEntry) -> Unit,
) : ComposeRoute, ComposeSceneRoute

@Deprecated(
message = """
Used as a backwards compatible for the old RouteBuilder APIs which do not expect the content to
be an extension function on AnimatedContentScope
""",
level = DeprecationLevel.WARNING,
)
internal fun sceneRouteWithoutAnimatedContent(
route: String,
deepLinks: List<String>,
navTransition: NavTransition?,
swipeProperties: SwipeProperties?,
content: @Composable (BackStackEntry) -> Unit,
): SceneRoute {
return SceneRoute(
route,
deepLinks,
navTransition,
swipeProperties,
content = { entry -> content(entry) }
)
}

0 comments on commit 2c4d92d

Please sign in to comment.