Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make scene provide an AnimatedContentScope to the composable content #312

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.floatingRouteWithoutAnimatedContent
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 Expand Up @@ -86,7 +119,8 @@ class RouteBuilder(
content: @Composable (BackStackEntry) -> Unit,
) {
addRoute(
FloatingRoute(
@Suppress("DEPRECATION")
floatingRouteWithoutAnimatedContent(
route = route,
content = content,
),
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,27 @@
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

@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 floatingRouteWithoutAnimatedContent(
route: String,
content: @Composable (BackStackEntry) -> Unit,
): FloatingRoute {
return FloatingRoute(
route = route,
content = { entry -> content(entry) },
)
}
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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to do something like what androidx.navigation does here https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt;l=57-60?q=%22ComposeNavigator.Destination(provider%22 which calls this internal deprecated function here https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigation/navigation-compose/src/main/java/androidx/navigation/compose/ComposeNavigator.kt;l=106-110 but for them it worked because the API also changed in a meaningful way besides just adding the AnimatedContentScope.

In our case here if I add it as a secondary constructor then there's ambiguity between the two of them and it's impossible to differentiate between the two. So I opted for an internal deprecated function to exist solely for this purpose.

route: String,
deepLinks: List<String>,
navTransition: NavTransition?,
swipeProperties: SwipeProperties?,
content: @Composable (BackStackEntry) -> Unit,
): SceneRoute {
return SceneRoute(
route,
deepLinks,
navTransition,
swipeProperties,
content = { entry -> content(entry) },
)
}