fix(home): 'Play now' resumes the waiting game, not the generic hub (B-002 P2)
Resolve the active session's gameType to its resume route (gameRouteFor) and carry it on HomeAction.gameRoute / HomeUiState.waitingGameRoute; HomeActionTarget.Game now navigates there (fallback Play hub). Each game screen auto-joins the couple's active session on open, so the Home 'Play now' CTA drops the user straight into the actual waiting game. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
1fe4dea9c1
commit
a94f44d3ec
|
|
@ -216,7 +216,8 @@ private fun HomeCallbacks.toActionHandler(onNavigate: (String) -> Unit): (HomeAc
|
|||
HomeActionTarget.QuestionPacks -> action.categoryId?.let(onCategory) ?: onPacks()
|
||||
HomeActionTarget.Settings -> onSettings()
|
||||
HomeActionTarget.AnswerReveal -> onReveal()
|
||||
HomeActionTarget.Game -> onNavigate(AppRoute.PLAY)
|
||||
// Resume the specific waiting game when known (B-002); fall back to the Play hub.
|
||||
HomeActionTarget.Game -> onNavigate(action.gameRoute ?: AppRoute.PLAY)
|
||||
HomeActionTarget.Challenge -> onNavigate(AppRoute.CONNECTION_CHALLENGES)
|
||||
HomeActionTarget.DatePlan -> onNavigate(AppRoute.DATE_MATCHES)
|
||||
HomeActionTarget.MemoryCapsule -> onNavigate(AppRoute.MEMORY_LANE)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ package app.closer.ui.home
|
|||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.closer.core.navigation.AppRoute
|
||||
import app.closer.crypto.CoupleEncryptionManager
|
||||
import app.closer.crypto.EncryptionStatus
|
||||
import app.closer.crypto.SealedRevealManager
|
||||
import app.closer.domain.model.GameType
|
||||
import app.closer.data.remote.FirestoreAnswerDataSource
|
||||
import app.closer.data.remote.FirestoreCapsuleDataSource
|
||||
import app.closer.data.remote.FirestoreChallengeDataSource
|
||||
|
|
@ -89,7 +91,10 @@ data class HomeAction(
|
|||
val target: HomeActionTarget,
|
||||
val tone: HomeActionTone,
|
||||
val metric: String? = null,
|
||||
val categoryId: String? = null
|
||||
val categoryId: String? = null,
|
||||
// For the "your partner is waiting to play" CTA: the specific game route to resume
|
||||
// (so "Play now" jumps into the actual waiting game, not the generic Play hub). B-002.
|
||||
val gameRoute: String? = null
|
||||
)
|
||||
|
||||
data class PendingActionCard(
|
||||
|
|
@ -99,6 +104,19 @@ data class PendingActionCard(
|
|||
val target: HomeActionTarget
|
||||
)
|
||||
|
||||
/**
|
||||
* The entry route that resumes an in-progress game of [gameType]. Each game screen
|
||||
* detects the couple's active session on open and joins it, so navigating here lets the
|
||||
* Home "Play now" CTA drop the user straight back into the waiting game (B-002).
|
||||
*/
|
||||
private fun gameRouteFor(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
|
||||
}
|
||||
|
||||
enum class DailyQuestionState {
|
||||
UNANSWERED,
|
||||
USER_ANSWERED_PARTNER_PENDING,
|
||||
|
|
@ -128,6 +146,9 @@ data class HomeUiState(
|
|||
val pendingActions: List<PendingActionCard> = emptyList(),
|
||||
// Retention signals — populated in loadHome() and observeAnswers()
|
||||
val hasWaitingGame: Boolean = false,
|
||||
// The route of the active game waiting for this user, so the Home "Play now" CTA
|
||||
// resumes that specific game instead of dumping on the generic Play hub (B-002).
|
||||
val waitingGameRoute: String? = null,
|
||||
val hasActiveChallenge: Boolean = false,
|
||||
val hasUpcomingDatePlan: Boolean = false,
|
||||
val hasUnlockedCapsule: Boolean = false,
|
||||
|
|
@ -243,6 +264,7 @@ class HomeViewModel @Inject constructor(
|
|||
|
||||
// Retention signal fetches — run in parallel, failures silently default to false.
|
||||
var hasWaitingGame = false
|
||||
var waitingGameRoute: String? = null
|
||||
var hasActiveChallenge = false
|
||||
var hasUpcomingDatePlan = false
|
||||
var hasUnlockedCapsule = false
|
||||
|
|
@ -252,8 +274,9 @@ class HomeViewModel @Inject constructor(
|
|||
val gameJob = async {
|
||||
runCatching {
|
||||
val session = questionSessionRepository.getActiveSessionForCouple(coupleId)
|
||||
session != null && uid !in session.completedByUsers
|
||||
}.getOrDefault(false)
|
||||
?.takeIf { uid !in it.completedByUsers }
|
||||
session to gameRouteFor(session?.gameType)
|
||||
}.getOrDefault(null to null)
|
||||
}
|
||||
val challengeJob = async {
|
||||
runCatching {
|
||||
|
|
@ -276,7 +299,9 @@ class HomeViewModel @Inject constructor(
|
|||
.any { it.status == "sealed" && it.unlockAt in 1L..now }
|
||||
}.getOrDefault(false)
|
||||
}
|
||||
hasWaitingGame = gameJob.await()
|
||||
val (waitingSession, waitingRoute) = gameJob.await()
|
||||
hasWaitingGame = waitingSession != null
|
||||
waitingGameRoute = waitingRoute
|
||||
hasActiveChallenge = challengeJob.await()
|
||||
hasUpcomingDatePlan = dateJob.await()
|
||||
hasUnlockedCapsule = capsuleJob.await()
|
||||
|
|
@ -295,6 +320,7 @@ class HomeViewModel @Inject constructor(
|
|||
partnerLeftEvent = false,
|
||||
needsRecovery = needsRecovery,
|
||||
hasWaitingGame = hasWaitingGame,
|
||||
waitingGameRoute = waitingGameRoute,
|
||||
hasActiveChallenge = hasActiveChallenge,
|
||||
hasUpcomingDatePlan = hasUpcomingDatePlan,
|
||||
hasUnlockedCapsule = hasUnlockedCapsule,
|
||||
|
|
@ -598,7 +624,8 @@ class HomeViewModel @Inject constructor(
|
|||
body = "A game is ready for the two of you. Jump back in and keep the ritual going.",
|
||||
cta = "Play now",
|
||||
target = HomeActionTarget.Game,
|
||||
tone = HomeActionTone.Ritual
|
||||
tone = HomeActionTone.Ritual,
|
||||
gameRoute = waitingGameRoute
|
||||
)
|
||||
|
||||
Priority.CHALLENGE_WAITING -> HomeAction(
|
||||
|
|
|
|||
Loading…
Reference in New Issue