diff --git a/navigation-compose/src/commonMain/kotlin/com.chrynan.navigation.compose/RememberComposeNavigatorUtils.kt b/navigation-compose/src/commonMain/kotlin/com.chrynan.navigation.compose/RememberComposeNavigatorUtils.kt index 361f6f3..bac8a09 100644 --- a/navigation-compose/src/commonMain/kotlin/com.chrynan.navigation.compose/RememberComposeNavigatorUtils.kt +++ b/navigation-compose/src/commonMain/kotlin/com.chrynan.navigation.compose/RememberComposeNavigatorUtils.kt @@ -4,6 +4,7 @@ package com.chrynan.navigation.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.chrynan.navigation.NavigationContext import com.chrynan.navigation.NavigationIntent import com.chrynan.navigation.Navigator @@ -57,9 +58,9 @@ fun rememberNavigatorByContent( * Example usage: * ```kotlin * val navigator = rememberNavigatorByContent( - * initialScope = BottomNavBarItem.HOME, - * initialKeysAndContent = { scope -> - * when (scope) { + * initialContext = BottomNavBarItem.HOME, + * initialContent = { context -> + * when (context) { * is BottomNavBarItem.HOME -> "Greeting" to { Text("Hello") } * } * } @@ -95,6 +96,53 @@ fun rememberNavigatorByContent( ) } +/** + * Creates and remembers a [ComposeNavigator] that can navigate with a key and [Composable] content. This allows for + * explicitly specifying the [Composable] content to navigate to at the [ComposeNavigatorByContent.goTo] function call + * site. Meaning the [Composable] content is more flexible and doesn't need to specified upfront when creating this + * [ComposeNavigatorByContent]. + * + * Example usage: + * ```kotlin + * val navigator = rememberNavigatorByContent( + * initialContext = BottomNavBarItem.HOME, + * initialContent = { context -> + * when (context) { + * is BottomNavBarItem.HOME -> "Greeting" to { Text("Hello") } + * } + * } + * ) + * + * // The NavContainer will start by displaying the initial content, which in this case is "Hello". + * NavContainer(navigator) + * + * // The above NavContainer will display "Good-bye" after the following call: + * navigator.goTo("Farewell") { Text("Good-bye") } + * + * // Goes back to the initial content: "Hello": + * navigator.goBack() + * ``` + * + * **Note:** That it is typical to use a [ComposeNavigator] with a [NavContainer] to display the [Composable] content + * and listen to changes. + * + * **Note:** That this function differs slightly from the [rememberNavigatorByContent] function in that this function + * allows changing of scopes, which is useful for more complex navigation. + * + * @see [rememberNavigatorByContent] + */ +@ExperimentalNavigationApi +@Composable +fun , Key> rememberNavigatorByContent( + initialContext: Context, + initialContent: (Context) -> @Composable ComposeNavigationContentScope.() -> Unit +): ComposeNavigatorByContentViewModel = remember { + ComposeNavigatorByContentViewModel( + initialContext = initialContext, + initialKeysAndContent = { it.initialKey to initialContent(it) } + ) +} + /** * Creates and remembers a [ComposeNavigator] that can navigate with a key. This allows for specifying the [Composable] * content up front when creating this [ComposeNavigatorByKey] and simply navigating with a key from the @@ -149,7 +197,7 @@ fun rememberNavigatorByKey( * Example usage: * ```kotlin * val navigator = rememberNavigatorByKey( - * initialScope = BottomNavBarItem.HELLO, + * initialContext = BottomNavBarItem.HELLO, * initialKeys = { scope -> * when(scope) { * BottomNavBarItem.HELLO -> "Greeting" @@ -176,7 +224,7 @@ fun rememberNavigatorByKey( * navigator.goBack() * * // Changes the scope to BottomNavBarItem.GOODBYE and displays its initial key, which in this case is "Farewell" - * navigator.changeScope(BottomNavBarItem.GOODBYE) + * navigator.changeContext(BottomNavBarItem.GOODBYE) * ``` * * **Note:** That it is typical to use a [ComposeNavigator] with a [NavContainer] to display the [Composable] content @@ -201,6 +249,58 @@ fun rememberNavigatorByKey( ) } +/** + * Creates and remembers a [ComposeNavigator] that can navigate with a key. This allows for specifying the [Composable] + * content up front when creating this [ComposeNavigatorByKey] and simply navigating with a key from the + * [ComposeNavigatorByKey.goTo] function. + * + * Example usage: + * ```kotlin + * val navigator = rememberNavigatorByKey( + * initialContext = BottomNavBarItem.HELLO, + * content = { key -> + * when(key) { + * "Greeting" -> Text("Hello") + * "Farewell" -> Text("Good-bye") + * else -> Text("Unexpected Key: $key") + * } + * } + * ) + * + * // The NavContainer will start by displaying the initial content, which in this case is "Hello" + * NavContainer(navigator) + * + * // The above NavContainer will display "Good Bye" after the following call: + * navigator.goTo("Farewell") + * + * // Goes back to the initial content: "Hello": + * navigator.goBack() + * + * // Changes the scope to BottomNavBarItem.GOODBYE and displays its initial key, which in this case is "Farewell" + * navigator.changeContext(BottomNavBarItem.GOODBYE) + * ``` + * + * **Note:** That it is typical to use a [ComposeNavigator] with a [NavContainer] to display the [Composable] content + * and listen to changes. + * + * **Note:** That this function differs slightly from the [rememberNavigatorByKey] function in that this function allows + * changing of scopes, which is useful for more complex navigation. + * + * @see [rememberNavigatorByKey] + */ +@ExperimentalNavigationApi +@Composable +fun , Key> rememberNavigatorByKey( + initialContext: Context, + content: @Composable ComposeNavigationKeyScope.(key: Key) -> Unit +): ComposeNavigatorByKeyViewModel = remember { + ComposeNavigatorByKeyViewModel( + initialScope = initialContext, + initialKeys = { it.initialKey }, + content = content + ) +} + /** * Creates and remembers a [ComposeNavigator] that can navigate with a [NavigationIntent] as a key. This allows for * specifying the [Composable] content up front when creating this [ComposeNavigatorByKey] and simply navigating with @@ -257,7 +357,7 @@ fun rememberNavigatorByIntent( * Example usage: * ```kotlin * val navigator = rememberNavigatorByKey( - * initialScope = BottomNavBarItem.HELLO, + * initialContext = BottomNavBarItem.HELLO, * initialKeys = { scope -> * when(scope) { * BottomNavBarItem.HELLO -> HomeNavigationIntent.Greeting @@ -304,3 +404,52 @@ fun rememberNavigatorByIntent( content = content ) } + +/** + * Creates and remembers a [ComposeNavigator] that can navigate with a [NavigationIntent] as a key. This allows for + * specifying the [Composable] content up front when creating this [ComposeNavigatorByKey] and simply navigating with + * a [NavigationIntent] key from the [ComposeNavigatorByKey.goTo] function. The returned [ComposeNavigator] implements + * the [Navigator] interface. + * + * Example usage: + * ```kotlin + * val navigator = rememberNavigatorByKey( + * initialContext = BottomNavBarItem.HELLO, + * content = { navigationIntent -> + * when(navigationIntent) { + * HomeNavigationIntent.Greeting -> Text("Hello") + * HomeNavigationIntent.Farewell -> Text("Good-bye") + * } + * } + * ) + * + * // The NavContainer will start by displaying the initial content, which in this case is "Hello" + * NavContainer(navigator) + * + * // The above NavContainer will display "Good Bye" after the following call: + * navigator.goTo(HomeNavigationIntent.Farewell) + * + * // Goes back to the initial content: "Hello": + * navigator.goBack() + * ``` + * + * **Note:** That it is typical to use a [ComposeNavigator] with a [NavContainer] to display the [Composable] content + * and listen to changes. + * + * **Note:** That this function differs slightly from the [rememberNavigatorByIntent] function in that this function + * allows changing of scopes, which is useful for more complex navigation. + * + * @see [rememberNavigatorByIntent] + */ +@ExperimentalNavigationApi +@Composable +fun , Intent : NavigationIntent> rememberNavigatorByIntent( + initialContext: Context, + content: @Composable ComposeNavigationIntentScope.(intent: Intent) -> Unit +): ComposeNavigationIntentNavigatorByKeyViewModel = remember { + ComposeNavigationIntentNavigatorByKeyViewModel( + initialScope = initialContext, + initialKeys = { it.initialKey }, + content = content + ) +} diff --git a/navigation-core/src/commonMain/kotlin/com.chrynan.navigation/NavigationContext.kt b/navigation-core/src/commonMain/kotlin/com.chrynan.navigation/NavigationContext.kt new file mode 100644 index 0000000..347a601 --- /dev/null +++ b/navigation-core/src/commonMain/kotlin/com.chrynan.navigation/NavigationContext.kt @@ -0,0 +1,16 @@ +package com.chrynan.navigation + +/** + * Represents a navigation context, or a container of a back stack of [Key]s. Navigation can take place within a + * [NavigationContext] typically by changing [Key] values. But an application may have multiple [NavigationContext]s + * that can be changed and navigated through. This allows for more complex navigation paradigms, such as retaining + * multiple back stacks for a bottom navigation UI component. + */ +interface NavigationContext { + + /** + * The initial key value that should be displayed when first changing to this [NavigationContext] before any other + * navigation was performed. + */ + val initialKey: Key +}