android-jetpack-composejetpack-compose-navigation

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

  • 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.