fix(games): add 'Join the game' escape to WaitingForPartner screen (B-004)
The generic WaitingForPartner screen only exited when the session became null, so a partner who landed there for an async game they could actually play (every current game is async — both play on their own device) was stuck waiting forever, recoverable only via Back to Games. Now the screen resolves the active session's game route and offers a primary 'Join the game' action that drops the user into the game (which auto-joins the session). Deterministic repro: QA starts How Well, Sam opens a different game -> one-game lock routes Sam to WaitingForPartner -> 'Join the game' -> How Well guess intro. Verified live. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
1b9d8cf8dc
commit
f1549c642c
|
|
@ -47,7 +47,13 @@ data class WaitingForPartnerUiState(
|
||||||
val isLoading: Boolean = true,
|
val isLoading: Boolean = true,
|
||||||
val gameType: String = GameType.WHEEL,
|
val gameType: String = GameType.WHEEL,
|
||||||
val partnerName: String = "Partner",
|
val partnerName: String = "Partner",
|
||||||
val navigateTo: String? = null
|
val navigateTo: String? = null,
|
||||||
|
/**
|
||||||
|
* Route into the partner's active game so this user can play their part, instead of being
|
||||||
|
* stuck on this "waiting" screen. Every current game is async (both play on their own device),
|
||||||
|
* so the partner who lands here can always join. Null only for an unknown game type. B-004.
|
||||||
|
*/
|
||||||
|
val joinRoute: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
|
|
@ -81,7 +87,8 @@ class WaitingForPartnerViewModel @Inject constructor(
|
||||||
it.copy(
|
it.copy(
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
gameType = session.gameType,
|
gameType = session.gameType,
|
||||||
partnerName = partnerName
|
partnerName = partnerName,
|
||||||
|
joinRoute = gameTypeRoute(session.gameType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,11 +180,30 @@ fun WaitingForPartnerScreen(
|
||||||
style = MaterialTheme.typography.bodySmall
|
style = MaterialTheme.typography.bodySmall
|
||||||
)
|
)
|
||||||
|
|
||||||
Button(
|
// Primary action: join the partner's game and play your part. Without this the
|
||||||
onClick = { onNavigate(AppRoute.PLAY) },
|
// screen was a dead-end for async games the user could actually play (B-004).
|
||||||
modifier = Modifier.fillMaxWidth()
|
state.joinRoute?.let { route ->
|
||||||
) {
|
Button(
|
||||||
Text("Back to Games")
|
onClick = { onNavigate(route) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("Join the game")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.joinRoute != null) {
|
||||||
|
TextButton(
|
||||||
|
onClick = { onNavigate(AppRoute.PLAY) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("Back to Games")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Button(
|
||||||
|
onClick = { onNavigate(AppRoute.PLAY) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("Back to Games")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TextButton(onClick = viewModel::abandonPartnerGame) {
|
TextButton(onClick = viewModel::abandonPartnerGame) {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -200,6 +226,15 @@ private fun gameTypeLabel(gameType: String): String = when (gameType) {
|
||||||
else -> gameType
|
else -> gameType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Entry route that joins the partner's active game (each game screen auto-joins on open). B-004. */
|
||||||
|
private fun gameTypeRoute(gameType: String): String? = when (gameType) {
|
||||||
|
GameType.WHEEL -> AppRoute.SPIN_WHEEL_RANDOM
|
||||||
|
GameType.THIS_OR_THAT -> AppRoute.THIS_OR_THAT
|
||||||
|
GameType.HOW_WELL -> AppRoute.HOW_WELL
|
||||||
|
GameType.DESIRE_SYNC -> AppRoute.DESIRE_SYNC
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
private fun gameTypeGlyphKey(gameType: String): String = when (gameType) {
|
private fun gameTypeGlyphKey(gameType: String): String = when (gameType) {
|
||||||
GameType.WHEEL -> "play"
|
GameType.WHEEL -> "play"
|
||||||
GameType.THIS_OR_THAT -> "question"
|
GameType.THIS_OR_THAT -> "question"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue