fix(nav): recovery back-stack loop + the Today tab's inconsistent back arrow
Two navigation fixes, one found the expensive way. 1. Post-recovery BACK bounced users to the Recovery screen, forever. The Home entry that routed to Recovery stayed on the back stack holding needsRecovery=true, and its LaunchedEffect re-fires whenever the entry is returned to — so after a successful recovery, BACK landed on stale-Home, which instantly redirected to Recovery again. It looks EXACTLY like the couple key was lost again (it wasn't; verified: the keyset survives process kill and cold-starts straight to Home). Cost an hour of key-loss ghost hunting live before the process-alive evidence gave it away. onRecovered and the partner-restore onDone now popUpTo(HOME) INCLUSIVE + launchSingleTop — the stale entry is replaced, not buried; BACK from Home exits the app like every other root tab. C-NAV-002 class; the restore variant was worse (it left Home AND Recovery underneath). 2. C-TODAY-BACK-001 (open P3 from the report): the Today tab drew a back arrow the other four tabs don't. DAILY_QUESTION is a bottom-nav tab — the bar IS the navigation. onBack is now nullable-defaulting-null and the nav wiring passes none; LocalQuestionContent already renders the arrow only when non-null. Verified live: no arrow, other tabs unchanged. Suite green, verified on-device (BACK exits; Today clean).
This commit is contained in:
parent
4856638097
commit
c636749cf3
|
|
@ -268,7 +268,9 @@ fun AppNavigation(
|
||||||
route = AppRoute.DAILY_QUESTION,
|
route = AppRoute.DAILY_QUESTION,
|
||||||
deepLinks = listOf(navDeepLink { uriPattern = "closer://closer.app/daily_question" })
|
deepLinks = listOf(navDeepLink { uriPattern = "closer://closer.app/daily_question" })
|
||||||
) {
|
) {
|
||||||
DailyQuestionScreen(onNavigate = navigateRoute, onBack = navigateBackOrHome)
|
// No onBack: it's a bottom-nav tab (C-TODAY-BACK-001 — the arrow made Today
|
||||||
|
// inconsistent with the other four tabs, whose bar IS the navigation).
|
||||||
|
DailyQuestionScreen(onNavigate = navigateRoute)
|
||||||
}
|
}
|
||||||
composable(route = AppRoute.QUESTION_PACKS) {
|
composable(route = AppRoute.QUESTION_PACKS) {
|
||||||
QuestionPackLibraryScreen(onNavigate = navigateRoute)
|
QuestionPackLibraryScreen(onNavigate = navigateRoute)
|
||||||
|
|
@ -409,8 +411,14 @@ fun AppNavigation(
|
||||||
composable(route = AppRoute.RECOVERY) {
|
composable(route = AppRoute.RECOVERY) {
|
||||||
RecoveryScreen(
|
RecoveryScreen(
|
||||||
onRecovered = {
|
onRecovered = {
|
||||||
|
// Pop up to and INCLUDING the old HOME, not just Recovery: the Home entry that
|
||||||
|
// routed here still holds needsRecovery=true, and its LaunchedEffect re-fires
|
||||||
|
// whenever it's returned to — so BACK from the new Home bounced users straight
|
||||||
|
// back to Recovery, forever, looking exactly like the key had been lost again
|
||||||
|
// (C-NAV-002 class; cost an hour of key-loss ghost-hunting live).
|
||||||
navController.navigate(AppRoute.HOME) {
|
navController.navigate(AppRoute.HOME) {
|
||||||
popUpTo(AppRoute.RECOVERY) { inclusive = true }
|
popUpTo(AppRoute.HOME) { inclusive = true }
|
||||||
|
launchSingleTop = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPartnerRestore = { navController.navigate(AppRoute.RESTORE_REQUEST) }
|
onPartnerRestore = { navController.navigate(AppRoute.RESTORE_REQUEST) }
|
||||||
|
|
@ -421,8 +429,11 @@ fun AppNavigation(
|
||||||
composable(route = AppRoute.RESTORE_REQUEST) {
|
composable(route = AppRoute.RESTORE_REQUEST) {
|
||||||
RestoreRequestScreen(
|
RestoreRequestScreen(
|
||||||
onDone = {
|
onDone = {
|
||||||
|
// Same stale-Home disease as onRecovered above — and worse: popping only this
|
||||||
|
// screen left BOTH the stale Home and the Recovery entry underneath.
|
||||||
navController.navigate(AppRoute.HOME) {
|
navController.navigate(AppRoute.HOME) {
|
||||||
popUpTo(AppRoute.RESTORE_REQUEST) { inclusive = true }
|
popUpTo(AppRoute.HOME) { inclusive = true }
|
||||||
|
launchSingleTop = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onBack = navigateBackOrHome
|
onBack = navigateBackOrHome
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ import app.closer.domain.model.Question
|
||||||
@Composable
|
@Composable
|
||||||
fun DailyQuestionScreen(
|
fun DailyQuestionScreen(
|
||||||
onNavigate: (String) -> Unit = {},
|
onNavigate: (String) -> Unit = {},
|
||||||
onBack: () -> Unit = {},
|
// Nullable, defaulting to none: DAILY_QUESTION is a bottom-nav TAB, and the bar is the navigation
|
||||||
|
// there — the other four tabs draw no back arrow, and LocalQuestionContent only renders one when
|
||||||
|
// onBack is non-null (C-TODAY-BACK-001). Pass a handler only from non-tab embeddings, if any ever exist.
|
||||||
|
onBack: (() -> Unit)? = null,
|
||||||
viewModel: DailyQuestionViewModel = hiltViewModel()
|
viewModel: DailyQuestionViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue