fix(nav): tab-switch routing prevents stacking tabs; fix(crash): runCatching around getUser/getCoupleForUser across 6 screens
This commit is contained in:
parent
fe1808b36c
commit
17c7ed60b9
|
|
@ -95,22 +95,32 @@ fun AppNavigation(
|
|||
val shellTitle = currentRoute
|
||||
?.takeIf { it in shellBackRoutes }
|
||||
?.let(AppRoute::titleFor)
|
||||
// Tab-switch semantics: pop to the graph start, keep a single instance, and
|
||||
// save/restore each tab's own back stack. Every navigation to a top-level
|
||||
// route must go through this so a tab is never pushed on top of another tab.
|
||||
val selectTab: (String) -> Unit = { route ->
|
||||
navController.navigate(route) {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
val navigateBackOrHome: () -> Unit = {
|
||||
if (!navController.popBackStack()) {
|
||||
navController.navigate(AppRoute.HOME) {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
selectTab(AppRoute.HOME)
|
||||
}
|
||||
}
|
||||
val navigateRoute: (String) -> Unit = { route ->
|
||||
if (route == "back") {
|
||||
navigateBackOrHome()
|
||||
} else {
|
||||
navController.navigate(route)
|
||||
when {
|
||||
route == "back" -> navigateBackOrHome()
|
||||
// Top-level tabs must use tab-switch semantics. Plain-navigating to a
|
||||
// tab (e.g. a "Game waiting" card → PLAY) would stack it on the current
|
||||
// tab; the bottom bar then saves that substack and `restoreState` later
|
||||
// lands the user on the wrong tab (Home → Play was the symptom).
|
||||
route in AppRoute.topLevelRoutes -> selectTab(route)
|
||||
else -> navController.navigate(route)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,15 +153,7 @@ fun AppNavigation(
|
|||
if (currentRoute in bottomRoutes) {
|
||||
AppBottomNavigation(
|
||||
currentRoute = currentRoute,
|
||||
onRouteSelected = { route ->
|
||||
navController.navigate(route) {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
onRouteSelected = selectTab
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ class GameSessionManager @Inject constructor(
|
|||
val activeSession = sessionRepository.getActiveSessionForCouple(couple.id)
|
||||
if (activeSession != null) {
|
||||
val partnerId = couple.userIds.firstOrNull { it != userId }
|
||||
val partnerName = partnerId?.let { userRepository.getUser(it) }?.displayName ?: "Partner"
|
||||
val partnerName = partnerId
|
||||
?.let { runCatching { userRepository.getUser(it) }.getOrNull() }
|
||||
?.displayName ?: "Partner"
|
||||
return Result.failure(
|
||||
Exception("partner_active_session|$partnerName|${gameTypeLabel(gameType)}")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1008,8 +1008,9 @@ class DSReplayViewModel @Inject constructor(
|
|||
return@launch
|
||||
}
|
||||
val partnerId = couple.userIds.firstOrNull { it != uid }
|
||||
val partnerName = partnerId?.let { gameSessionManager.getUser(it) }?.displayName
|
||||
?: "Your partner"
|
||||
val partnerName = partnerId
|
||||
?.let { runCatching { gameSessionManager.getUser(it) }.getOrNull() }
|
||||
?.displayName ?: "Your partner"
|
||||
_uiState.update { it.copy(partnerName = partnerName) }
|
||||
|
||||
val session = sessionRepository.getSessionById(couple.id, sessionId) ?: run {
|
||||
|
|
|
|||
|
|
@ -62,11 +62,16 @@ class WaitingForPartnerViewModel @Inject constructor(
|
|||
init {
|
||||
viewModelScope.launch {
|
||||
val userId = gameSessionManager.currentUserId ?: return@launch
|
||||
val couple = gameSessionManager.getCoupleForUser(userId) ?: return@launch
|
||||
val couple = runCatching { gameSessionManager.getCoupleForUser(userId) }.getOrNull()
|
||||
?: return@launch
|
||||
coupleId = couple.id
|
||||
|
||||
val partnerId = couple.userIds.firstOrNull { it != userId }
|
||||
val partnerName = partnerId?.let { gameSessionManager.getUser(it) }?.displayName ?: "Partner"
|
||||
// getUser() throws on Firestore failure (e.g. PERMISSION_DENIED); never let
|
||||
// that escape this launch or the whole app crashes on the waiting screen.
|
||||
val partnerName = partnerId
|
||||
?.let { runCatching { gameSessionManager.getUser(it) }.getOrNull() }
|
||||
?.displayName ?: "Partner"
|
||||
|
||||
gameSessionManager.observeActiveSession(couple.id).collect { session ->
|
||||
if (session == null) {
|
||||
|
|
|
|||
|
|
@ -1179,8 +1179,9 @@ class HowWellReplayViewModel @Inject constructor(
|
|||
return@launch
|
||||
}
|
||||
val partnerId = couple.userIds.firstOrNull { it != uid }
|
||||
val partnerName = partnerId?.let { gameSessionManager.getUser(it) }?.displayName
|
||||
?: "Your partner"
|
||||
val partnerName = partnerId
|
||||
?.let { runCatching { gameSessionManager.getUser(it) }.getOrNull() }
|
||||
?.displayName ?: "Your partner"
|
||||
_uiState.update { it.copy(partnerName = partnerName) }
|
||||
|
||||
val session = sessionRepository.getSessionById(couple.id, sessionId) ?: run {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class PairingSuccessViewModel @Inject constructor(
|
|||
init {
|
||||
viewModelScope.launch {
|
||||
val myId = authRepository.currentUserId ?: return@launch
|
||||
val me = userRepository.getUser(myId)
|
||||
val me = runCatching { userRepository.getUser(myId) }.getOrNull()
|
||||
val couple = coupleRepository.getCoupleForUser(myId)
|
||||
val partnerId = couple?.userIds?.firstOrNull { it != myId }
|
||||
val partner = partnerId?.let { runCatching { userRepository.getUser(it) }.getOrNull() }
|
||||
|
|
|
|||
|
|
@ -1249,8 +1249,9 @@ class ThisOrThatReplayViewModel @Inject constructor(
|
|||
return@launch
|
||||
}
|
||||
val partnerId = couple.userIds.firstOrNull { it != uid }
|
||||
val partnerName = partnerId?.let { gameSessionManager.getUser(it) }?.displayName
|
||||
?: "Your partner"
|
||||
val partnerName = partnerId
|
||||
?.let { runCatching { gameSessionManager.getUser(it) }.getOrNull() }
|
||||
?.displayName ?: "Your partner"
|
||||
_uiState.update { it.copy(partnerName = partnerName) }
|
||||
|
||||
val session = sessionRepository.getSessionById(couple.id, sessionId) ?: run {
|
||||
|
|
|
|||
Loading…
Reference in New Issue