Tlaster / PreCompose

Compose Multiplatform Navigation && State Management
https://tlaster.github.io/PreCompose/
MIT License
801 stars 47 forks source link

[BUG] Nested Navigation Group with Bottom Navigation #309

Open iamnaran opened 2 months ago

iamnaran commented 2 months ago

Describe the bug Let's say we've login flow, and once the user successfully logs in, they land on the main screen. However, when setting up two navigation groups within a NavHost, I'm encountering an issue where the start destination item in the bottom navigation isn't being automatically selected when navigating to that group route.

To Reproduce Create two groups with one being BottomNavigation

@Composable
fun RootNavHost(navigator: Navigator) {
    NavHost(
        navigator = navigator,
        navTransition = NavTransition(),
        initialRoute = AppScreen.Auth.route,
    ) {

        group(
            route = AppScreen.Auth.route,
            initialRoute = AppScreen.Auth.Login.route
        ) {
            scene(
                route = AppScreen.Auth.Login.route,
                navTransition = NavTransition(),
            ) {
                LoginScreen(navigateToHome = {
                    navigator.navigate(AppScreen.Main.route)
                }, navigateToSignUp = {

                })
            }
        }

        group(
            route = AppScreen.Main.route,
            initialRoute = AppScreen.Main.Home.route,
        ) {

            scene(
                route = AppScreen.Main.Home.route,
                navTransition = NavTransition(),
            ) {

                HomeScreen(onProductClick = {

                })

            }

            scene(
                route = AppScreen.Main.Notification.route,
                navTransition = NavTransition(),
            ) {
                NotificationScreen()
            }

            scene(
                route = AppScreen.Main.Profile.route,
                navTransition = NavTransition(),
            ) {
                ProfileScreen()
            }

            }

        }

    }

}

@Composable
fun currentRoute(navigator: Navigator): String? {
    return navigator.currentEntry.collectAsState(null).value?.route?.route

}

And BottomAppBar.kt

@Composable
fun BottomBar(
    navigator: Navigator,
) {
    val navigationScreen = listOf(
        AppScreen.Main.Home,
        AppScreen.Main.Notification,
        AppScreen.Main.Explore,
        AppScreen.Main.Profile
    )

    NavigationBar {
        navigationScreen.forEach {
            NavigationBarItem(label = { Text(text = it.title) },
                selected = it.route == currentRoute(navigator),
                onClick = {
                    navigator.navigate(
                        it.route,
                        NavOptions(
                            launchSingleTop = true,
                        ),
                    )
                })
        }
    }
}

But when navigating to the initial route destination of the group, it works.

      navigator.navigate(AppScreen.Main.Home.route)

Expected behavior When moving to the destination to a group, the initial route of group should correspond to the initial route, correct? I believe in Jetpack Compose Navigation, this functionality operates by navigating to the navigation route. But here i have to navigate to the initial route of the group.

      navigator.navigate(AppScreen.Main.route)

Minimal reproducible example Here's Github Repo Link - https://github.com/iamnaran/jellyfish/tree/main

Tlaster commented 2 months ago

Since PreCompose treats the group as a single route, so the currentRoute when you navigate to AppScreen.Main.route will be AppScreen.Main.route, not AppScreen.Main.Home.route, a workaround is to check both AppScreen.Main.route and AppScreen.Main.Home.route. It can be fixed by changing currentRoute to the actual scene behind the group, but this will change the current behavior and I wonder if anyone is using such a behavior.

kagg886 commented 3 weeks ago

the 'group()' simliar to provide a route alias, because this api don't deal in it's closure to complete your goal, you should use in this way:

NavHost(
            navigator = navigator,
            navTransition = NavTransition(),
            initialRoute = "/home",
        ) {
            scene(
                route = "/home",
                navTransition = NavTransition(),
            ) {
                Text(text = "Hello!")
            }

            group("/item", "/item/1") {
                for (i in 1..10) {
                    scene("/item/$i") {
                        Text("Hello $i")
                    }
                }
            }
        }

then you can navigate it like nested navigation:

navigator.navigate("/item/2")