'Jetpack Compose navigation: login screen and different screen with bottom navigation

My goal is to to have a LoginScreen from which I can navigate to an InternalScreen. The InternalScreen should have/be a bottom navigation bar that can navigate to multiple other screens/routes in the internal space.

This is what I imagined my NavGraph was supposed to look like:

 - LoginScreen
 - internal space
   - InternalScreen with BottomNavigation
     - some fragment
     - some other fragment 

My idea was to create a Scaffold with a BottomNavigationBar in the InternalScreen composable but I do not no where to put it in my NavGraph since said NavGraph also has to contain the different routes for the BottomNavigationBar.

How should I approach this? I am sorry if this has already been answered, I couldn't find anything about this particular case.



Solution 1:[1]

I think the login screen/flow must be part of the application navigation flow. In summary, your application must react to a isLoggedIn state, which should be global, and in case of the user is not logged in, the login screen must be displayed.

This is what I did:

@Composable
fun MainNavigation(
    viewModel: MainViewModel,
    navController: NavHostController,
) {
    val auth = viewModel.auth
    val initialRoute =
        if (auth.isLoggedIn()) BooksFeature.route else LoginFeature.route

    AnimatedNavHost(
        navController,
        startDestination = initialRoute
    ) {
        loginGraph(auth, navController)
        booksGraph(auth, navController)
        settingsGraph(navController)
    }
}

The MainNavigation composable is the root of my app (which is called in setContent at MainActivity). Each feature of the app has a navigation graph. Like booksGraph:

fun NavGraphBuilder.booksGraph(
    auth: Auth, // this is a simple class which 
                // knows if the user is logged in
    navController: NavHostController
) {
    navigation(
        route = BooksFeature.route,
        startDestination = BooksList.route,
    ) {
        composable("ScreenA") {
            ScreenA()
        }
        ...
    }
}

In my activity (I'm using just one activity), I'm observing the login state and redirecting to the login screen properly.

private fun launchLoginObserver() {
    lifecycleScope.launch(Dispatchers.Main) {
        mainViewModel.isLoggedIn.collect { isLoggedInState ->
            if (isLoggedInState == false) {
                navigationController.navigate(LoginScreen.route) {
                    popUpTo(0) // reset stack
                }
            }
        }
    }
}

If you want to take a look into the full implementation, here is the link for my repository.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 nglauber