White screen and app freez when click on top navigation button twice in Android Jetpack Compose App

8 hours ago 1
ARTICLE AD BOX

In my app, I am using TopAppBar that has a humburger icon and NavigationView (ModalNavigationDrawer + ModalDrawerSheet) , the probelm is when I click twice in nav icon or when I click on the navigation icon in the settings screen, then click again on the navigation icon of home. Strange behavior occurs when the app is showig white screen, like freezing, and I got no error or exception

Here's a GIF showing the problem

My code:

MainAppNavGraph

@Composable fun MainAppNavGraph( currentUser: FirebaseUser?, onLogout: () -> Unit, networkStatus: NetworkStatus, snackbarHostState: SnackbarHostState ) { val navController = rememberNavController() val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() val context = LocalContext.current val currentBackStack by navController.currentBackStackEntryAsState() val currentRoute = currentBackStack?.destination?.route val drawerItems = listOf( DrawerItem("home", "Home", Icons.Default.Home, route = Routes.HomeScreen.route), DrawerItem("profile", "Profile", Icons.Default.Person, route = Routes.ProfileScreen.route), DrawerItem( "leader_board", "Leader Board", Icons.Default.Leaderboard, route = Routes.LeaderboardScreen.route ), DrawerItem( "remove_ads_for_30_mins", "Remove Ads?", iconRes = R.drawable.ad_blocker, route = null ), DrawerItem( id = "settings", title = "Settings", iconImageVector = Icons.Default.Settings, route = Routes.SettingsScreen.route ) ) val authViewModel = hiltViewModel<AuthViewModel>() val userState by authViewModel.userData.collectAsState() val quizViewModel = hiltViewModel<QuizViewModel>() var drawerGesturesEnabled by remember { mutableStateOf(true) } LaunchedEffect(currentUser?.uid) { currentUser?.uid?.let { authViewModel.loadUserData(it) } } LaunchedEffect(currentRoute) { drawerGesturesEnabled = (currentRoute != Routes.PrivacyPolicyScreen.route && currentRoute != Routes.TermsAndConditionsScreen.route) if (currentRoute == Routes.PrivacyPolicyScreen.route || currentRoute == Routes.TermsAndConditionsScreen.route ) { scope.launch { drawerState.close() } } } val userName = (userState as? Resource.Success<User>)?.data?.userName ?: "No User Logged" val userEmail = (userState as? Resource.Success)?.data?.email ?: "No Email" ModalNavigationDrawer( drawerState = drawerState, gesturesEnabled = drawerGesturesEnabled, drawerContent = { ModalDrawerSheet( windowInsets = WindowInsets(0, 0, 0, 0), drawerContainerColor = MaterialTheme.colorScheme.surface, ) { AppDrawer( currentRoute = currentRoute ?: Routes.HomeScreen.route, userName = userName, // ← من ViewModel لاحقاً userEmail = userEmail, drawerItems = drawerItems, onItemClick = { item -> item.route?.let { navController.navigate(it) { popUpTo(Routes.HomeScreen.route) { saveState = true } launchSingleTop = true restoreState = true } } }, onLogoutClick = { scope.launch { drawerState.close() } authViewModel.logout() onLogout() }, onCloseDrawer = { scope.launch { drawerState.close() } }, onRemoveAdsClick = { if (AdManager.areAdsDisabled()) { Toast.makeText( context, "Ads disabled — ${AdManager.getRemainingMinutes()} minutes remaining", Toast.LENGTH_SHORT ).show() } else if (AdManager.isRewardedReady()) { AdManager.showRewardedAd( activity = context as Activity, onSessionActivated = { remaining -> Toast.makeText( context, "🎉 Ads disabled for $remaining minutes!", Toast.LENGTH_LONG ).show() }, onNotReady = { Toast.makeText( context, "Ad not ready, try again", Toast.LENGTH_SHORT ).show() AdManager.loadRewardedAd(context) } ) } else { Toast.makeText(context, "Loading ad, try again", Toast.LENGTH_SHORT) .show() AdManager.loadRewardedAd(context) } } ) } } ) { NavHost( navController = navController, startDestination = Routes.HomeScreen.route ) { composable(route = Routes.HomeScreen.route) { val homeScreenViewModel = hiltViewModel<HomeScreenViewModel>() val state by homeScreenViewModel.homeState.collectAsState() var isDrawerOpening by remember { mutableStateOf(false) } HomeScreen( stateHomeScreen = state, event = homeScreenViewModel::onEvent, navController = navController, onMenuClick = { if (!isDrawerOpening && !drawerState.isOpen) { isDrawerOpening = true scope.launch { drawerState.open() isDrawerOpening = false } } }, networkStatus = networkStatus, snackbarHostState = snackbarHostState ) } composable( route = Routes.QuizScreen.route, arguments = listOf( navArgument(ARG_KEY_QUIZ_NUMBER) { type = NavType.IntType }, navArgument(ARG_KEY_QUIZ_CATEGORY) { type = NavType.StringType }, navArgument(ARG_KEY_QUIZ_DIFFICULTY) { type = NavType.StringType }, navArgument(ARG_KEY_QUIZ_TYPE) { type = NavType.StringType }, ) ) { val state by quizViewModel.quizList.collectAsState() QuizScreen( numberOfQuizzes = it.arguments?.getInt(ARG_KEY_QUIZ_NUMBER)!!, quizCategory = it.arguments?.getString(ARG_KEY_QUIZ_CATEGORY)!!, quizDifficulty = it.arguments?.getString(ARG_KEY_QUIZ_DIFFICULTY)!!, quizType = it.arguments?.getString(ARG_KEY_QUIZ_TYPE)!!, event = quizViewModel::onEvent, state = state, navController = navController ) } composable( route = Routes.ScoreScreen.route, arguments = listOf( navArgument(NOQ_KEY) { type = NavType.IntType }, navArgument(CORRECT_ANSWERS_KEY) { type = NavType.IntType } ) ) { ScoreScreen( numberOfQuestions = it.arguments?.getInt(NOQ_KEY)!!, numberOfCorrectAnswers = it.arguments?.getInt(CORRECT_ANSWERS_KEY)!!, onClose = { navController.navigate(Routes.HomeScreen.route) { popUpTo(Routes.HomeScreen.route) { inclusive = true } } }, quizStates = quizViewModel.quizList.collectAsState().value.quizState, onReviewAnswers = { navController.navigate(Routes.ReviewAnswersScreen.route) } ) } composable(route = Routes.LeaderboardScreen.route) { LeaderboardScreen() } composable(route = Routes.SettingsScreen.route) { SettingsScreen( onBackClick = { navController.popBackStack() }, onPrivacyPolicyClick = { navController.navigate(Routes.PrivacyPolicyScreen.route) }, onTermsClick = { navController.navigate(Routes.TermsAndConditionsScreen.route) } ) } composable(route = Routes.ProfileScreen.route) { ProfileScreen( userName = userName, userEmail = userEmail, onLogoutClick = { scope.launch { drawerState.close() } authViewModel.logout() onLogout() } ) } composable(route = Routes.ReviewAnswersScreen.route) { val state by quizViewModel.quizList.collectAsState() // instance ReviewAnswersScreen( quizStates = state.quizState, onBack = { navController.popBackStack() } ) } composable(route = Routes.PrivacyPolicyScreen.route) { PrivacyPolicyScreen { navController.popBackStack() } } composable(route = Routes.TermsAndConditionsScreen.route) { TermsAndConditionsScreen { navController.popBackStack() } } } } }

HomeHeader

@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeHeader( onMenuClicked: () -> Unit = {}, onSettingsClicked: () -> Unit = {} ) { TopAppBar( title = { Text( modifier = Modifier.fillMaxWidth(), text = "Quizzy", fontSize = HeroTextSize, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.secondary, textAlign = TextAlign.Center ) }, navigationIcon = { IconButton( onClick = onMenuClicked, modifier = Modifier .size(40.dp) .padding(start = 8.dp), ) { Icon( imageVector = Icons.Default.Menu, contentDescription = "Menu", tint = MaterialTheme.colorScheme.secondary, ) } }, actions = { IconButton(onClick = onSettingsClicked) { Icon( contentDescription = "Settings", tint = colorResource(R.color.colorSecondary), imageVector = Icons.Default.Settings, ) } }, colors = TopAppBarDefaults.topAppBarColors( containerColor = colorResource(R.color.colorPrimaryVariant) ), modifier = Modifier.clip( RoundedCornerShape( bottomStart = Dimens.LargeCornerRadius, bottomEnd = Dimens.LargeCornerRadius ) ) ) }
Read Entire Article