简体   繁体   中英

Skip landing page in NavHost when user opens the app for second time using Jetpack Compose with Flow

I have an app with HorizontalPager at startDestination screen and after I go to the last page, the app shows the home page. When I open the app for second time it should show Home page immediately and never again show that startDestination screen with HorizontalPager . I used dataStore and it works, but the problem is that every time I open the app it flashes for a second that HorizontalPager landing page and then it switches to the home page. I used flow to get true/false state of the app start, so it will know it will know app was already opened for first time.

class MainActivity : ComponentActivity() {
    @ExperimentalAnimationApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            WebSafeTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    val navController = rememberNavController()
                    Navigation(navController)
                }
            }
        }
    }
}

@ExperimentalAnimationApi
@ExperimentalMaterialApi
@ExperimentalFoundationApi
@ExperimentalPagerApi
@Composable
fun Navigation(
    navController: NavHostController
    ) {
    val context = LocalContext.current
    val preferencesManager = PreferencesManager(context)
    val preferencesFlow = preferencesManager.preferencesFlow
    val scope = rememberCoroutineScope()
    val result = remember { mutableStateOf(Constants.SKIP_LANDING_PAGE) }
    scope.launch {
        result.value = preferencesFlow.first().skipLandingPage
    }

    NavHost(
        navController = navController,
//it goes it this line 2 times, first time when the app opens and second time after the flow is finished
        startDestination = if (result.value) Screen.HomeScreen.route else Screen.LandingScreen.route,
        modifier = Modifier.fillMaxSize()
    ) {
        composable(
            route = Screen.LandingScreen.route
        ) {
            Landing(navController)
        }
        composable(
            route = Screen.SkipChooseCountryScreen.route
        ) {
            ChooseCountry()
        }
        composable(
            route = Screen.HomeScreen.route
        ) {
            Home(navController)
        }
    }
}

It goes to NavHost for the first time after app openes and it always returns FALSE as it is default value, after that flow returns TRUE(so it knows app was opened at least once before) and then it openes the correct screen.

I have no idea how to make NavHost to wait that flow to finishes. I tried to put NavHost into the scope but it didn't allow me.

I also need to read data from data store, so this is how I do it:

Crossfade(
    targetState = state.value.loadState
) { loadState ->
    when (loadState) {
        LoadState.NOT_LOADED -> Box(modifier = Modifier.fillMaxSize())
        LoadState.SHOW_PIN -> PinScreen(
            loadState = loadState,
            state = state,
            modifier = Modifier.fillMaxSize(),
        )
        LoadState.SHOW_CONTENT -> MainContent(
            state = state,
        )
    }
}

Initially my state is NOT_LOADED so I just display an empty box that fills the screen. You could alternatively display a spinner, or your app's logo. Once the data has been loaded, I show the PIN screen if the user has PIN enabled, or the main screen otherwise.

Also, note that you should not have your viewpager screen as your root destination, your home page should be your root destination, and you should conditionally navigate to the viewpager if the user has not seen your onboarding flow yet. Check this for details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM