diff --git a/decompose-navhost/build.gradle.kts b/decompose-navhost/build.gradle.kts index 74781b6..8f513e4 100644 --- a/decompose-navhost/build.gradle.kts +++ b/decompose-navhost/build.gradle.kts @@ -48,6 +48,9 @@ kotlin { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material3) + + implementation(libs.uri) + implementation(libs.napier) } commonTest.dependencies { implementation(libs.kotlin.test) @@ -78,7 +81,7 @@ val androidSourceJar by tasks.registering(Jar::class) { val GROUP_ID = "io.github.blucky8649" val ARTIFACT_ID = "decompose-navhost" -val VERSION = "1.0.0-alpha03" +val VERSION = "1.0.0-alpha04" mavenPublishing { coordinates(GROUP_ID, ARTIFACT_ID, VERSION) diff --git a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/Destination.kt b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/Destination.kt index 5fb13a0..a3f7068 100644 --- a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/Destination.kt +++ b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/Destination.kt @@ -2,9 +2,13 @@ package com.blucky8649.decompose_navhost.navigation import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.runtime.Composable +import com.eygraber.uri.Uri data class Destination( - val name: String, + private val name: String, internal val content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit = {} -) +) { + val route get() = Uri.parse(name).host ?: name + internal val fullRoute get() = name +} diff --git a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavBackStackEntry.kt b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavBackStackEntry.kt index d28b030..74dc34e 100644 --- a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavBackStackEntry.kt +++ b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavBackStackEntry.kt @@ -1,10 +1,26 @@ package com.blucky8649.decompose_navhost.navigation import com.blucky8649.decompose_navhost.utils.randomUuid +import com.blucky8649.decompose_navhost.utils.withScheme +import com.eygraber.uri.Uri data class NavBackStackEntry( val destination: Destination, val id: String = randomUuid, - val navOptions: NavOptions + val navOptions: NavOptions, + val arguments: NavArguments ) +class NavArguments(route: String) { + private val routeUri = Uri.parse(withScheme(route)) + private val arguments get() = routeUri.getQueryParameterNames() + .associateWith { routeUri.getQueryParameter(it) } + + fun getString(key: String) = arguments[key] + fun getInt(key: String) = runCatching { arguments[key]?.toInt() }.getOrNull() + fun getLong(key: String) = runCatching { arguments[key]?.toLong() }.getOrNull() + fun getFloat(key: String) = runCatching { arguments[key]?.toFloat() }.getOrNull() + fun getDouble(key: String) = runCatching { arguments[key]?.toDouble() }.getOrNull() + fun getBoolean(key: String) = runCatching { arguments[key]?.toBoolean() }.getOrNull() +} + diff --git a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavController.kt b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavController.kt index 6aa0bad..630426e 100644 --- a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavController.kt +++ b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavController.kt @@ -11,6 +11,7 @@ import com.arkivanov.decompose.router.stack.popWhile import com.arkivanov.decompose.router.stack.push import com.arkivanov.decompose.value.Value import com.arkivanov.essenty.backhandler.BackHandlerOwner +import com.blucky8649.decompose_navhost.utils.withScheme class NavController( componentContext: ComponentContext @@ -37,7 +38,8 @@ class NavController( childFactory = { config, _ -> NavBackStackEntry( destination = config.destination, - navOptions = config.navOptions + navOptions = config.navOptions, + arguments = NavArguments(config.fullRoute) ) } ) @@ -55,7 +57,7 @@ class NavController( } navigation.popWhile { (topDestinationOfStack, _) -> - topDestinationOfStack.name != popUpToRoute + topDestinationOfStack.fullRoute != popUpToRoute } if (inclusive) { navigation.pop(onComplete = onCompleted) } @@ -71,7 +73,8 @@ class NavController( val newConfig = NavConfiguration( destination = graph.findDestination(route), - navOptions = navOptions + navOptions = navOptions, + fullRoute = withScheme(route) ) navigation.push(newConfig) @@ -80,7 +83,8 @@ class NavController( data class NavConfiguration( val destination: Destination, - val navOptions: NavOptions = NavOptions() + val navOptions: NavOptions = NavOptions(), + val fullRoute: String = destination.route ) @Composable diff --git a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavGraph.kt b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavGraph.kt index 5e380e9..f6c8470 100644 --- a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavGraph.kt +++ b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/navigation/NavGraph.kt @@ -2,13 +2,21 @@ package com.blucky8649.decompose_navhost.navigation import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.runtime.Composable +import com.blucky8649.decompose_navhost.utils.withScheme +import com.eygraber.uri.Uri +import io.github.aakira.napier.Napier + +const val SCHEME = "navhost://" class NavGraph ( val startDestination: String, private val destinations: Map ) { - fun findDestination(route: String) : Destination = destinations[route] - ?: error("Destination not found") + fun findDestination(route: String): Destination { + val uri = Uri.parse(withScheme(route)) + val host = uri.host + return destinations[host] ?: error("Destination not found") + } } class NavGraphBuilder { @@ -24,7 +32,9 @@ class NavGraphBuilder { route: String, content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit ) { - destinations[route] = Destination(route, content = content) + val fullRoute = withScheme(route) + val host = Uri.parse(fullRoute).host ?: route + destinations[host] = Destination(fullRoute, content = content) } internal fun build() = NavGraph(startDestination, destinations) diff --git a/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/utils/NavUtils.kt b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/utils/NavUtils.kt new file mode 100644 index 0000000..16d01fa --- /dev/null +++ b/decompose-navhost/src/commonMain/kotlin/com/blucky8649/decompose_navhost/utils/NavUtils.kt @@ -0,0 +1,5 @@ +package com.blucky8649.decompose_navhost.utils + +import com.blucky8649.decompose_navhost.navigation.SCHEME + +fun withScheme(route: String) = if (route.startsWith(SCHEME)) route else "$SCHEME$route" \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e46b234..bd564f9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,9 @@ essenty = "2.2.0-beta01" androidx-activityCompose = "1.9.2" lifecycleRuntimeKtx = "2.8.6" cupertino = "0.1.0-alpha04" -nexus-publish = "0.28.0" +nexus-publish = "0.29.0" +uri-kmp = "0.0.18" +napier = "2.7.1" [libraries] kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } @@ -27,7 +29,9 @@ decompose = { module = "com.arkivanov.decompose:decompose", version.ref = "decom decompose-extension-compose = { module = "com.arkivanov.decompose:extensions-compose", version.ref = "decompose" } decompose-extension-compose-experimental = { module = "com.arkivanov.decompose:extensions-compose-experimental", version.ref = "decompose" } decompose-extension-android = { module = "com.arkivanov.decompose:extensions-android", version.ref = "decompose" } -decompose-essenty = { module = "com.arkivanov.essenty:lifecycle", version.ref = "essenty" } +uri = { module = "com.eygraber:uri-kmp", version.ref = "uri-kmp" } +napier = { module = "io.github.aakira:napier", version.ref = "napier"} + cupertino-navigation = { module = "io.github.alexzhirkevich:cupertino-decompose", version.ref = "cupertino"} diff --git a/shared/src/commonMain/kotlin/com/blucky8649/decompose_navhost/SampleApp.kt b/shared/src/commonMain/kotlin/com/blucky8649/decompose_navhost/SampleApp.kt index d26fe31..0cdbe08 100644 --- a/shared/src/commonMain/kotlin/com/blucky8649/decompose_navhost/SampleApp.kt +++ b/shared/src/commonMain/kotlin/com/blucky8649/decompose_navhost/SampleApp.kt @@ -82,11 +82,14 @@ fun SampleApp( "navigate to B", this ) { - navController.navigate("detailB") + navController.navigate("detailB?name=screenB&id=123") } } - composable("detailB") { + composable("detailB?id={id}&name={name}") { + val id = it.arguments.getInt("id") + val name = it.arguments.getString("name") + println("backStack = ${it.id}, id = $id, name = $name") DetailsComponent( "detailB", "navigate to C", @@ -131,7 +134,7 @@ fun BackStackTracker(navController: NavController) { Box(Modifier.fillMaxSize()) { LazyRow(Modifier.fillMaxWidth().align(Alignment.BottomCenter)) { items(items.size) { - val route = items[it].destination.name + val route = items[it].destination.route Text(route, modifier = Modifier.background(Color.LightGray)) Spacer(Modifier.width(10.dp)) }