feat(date-memories): add date reflection pending computation to HomeViewModel

This commit is contained in:
null 2026-06-30 18:14:21 -05:00
parent 9b5f6b4eb3
commit c056f6a7a1
1 changed files with 41 additions and 3 deletions

View File

@ -70,7 +70,8 @@ enum class HomeActionTarget {
Game,
Challenge,
DatePlan,
MemoryCapsule
MemoryCapsule,
DateMemories
}
enum class HomeActionTone {
@ -158,6 +159,8 @@ data class HomeUiState(
val hasActiveChallenge: Boolean = false,
val hasUpcomingDatePlan: Boolean = false,
val hasUnlockedCapsule: Boolean = false,
// A completed date this user hasn't reflected on yet (drives the Home "reflect on your date" nudge).
val hasPendingDateReflection: Boolean = false,
val weeklyRecapReady: Boolean = false,
val reminderSentEvent: Boolean = false,
/** "Thinking of you" nudge: in-flight guard + one-shot snackbar message (success or friendly error). */
@ -192,7 +195,9 @@ class HomeViewModel @Inject constructor(
private val outcomeRepository: OutcomeRepository,
private val settingsRepository: SettingsRepository,
private val activityDataSource: app.closer.data.remote.FirestoreActivityDataSource,
private val dailyQuestionResolver: app.closer.domain.usecase.DailyQuestionResolver
private val dailyQuestionResolver: app.closer.domain.usecase.DailyQuestionResolver,
private val dateMemoryDataSource: app.closer.data.remote.FirestoreDateMemoryDataSource,
private val dateReflectionDataSource: app.closer.data.remote.FirestoreDateReflectionDataSource
) : ViewModel() {
private val _uiState = MutableStateFlow(HomeUiState())
@ -289,6 +294,7 @@ class HomeViewModel @Inject constructor(
var hasActiveChallenge = false
var hasUpcomingDatePlan = false
var hasUnlockedCapsule = false
var hasPendingDateReflection = false
val coupleId = couple?.id
if (couple != null && coupleId != null && uid != null) {
coroutineScope {
@ -320,6 +326,16 @@ class HomeViewModel @Inject constructor(
.any { it.status == "sealed" && it.unlockAt in 1L..now }
}.getOrDefault(false)
}
// Pending date reflection: the most recent completed date this user hasn't
// reflected on yet. The nudge chases the latest date; older un-reflected dates
// remain reachable from the Replay timeline.
val reflectionJob = async {
runCatching {
val latest = dateMemoryDataSource.getHistoryOnce(coupleId).firstOrNull()
latest != null &&
!dateReflectionDataSource.hasReflected(coupleId, latest.id, uid)
}.getOrDefault(false)
}
val (waitingSession, waitingRoute) = gameJob.await()
hasWaitingGame = waitingSession != null
waitingGameRoute = waitingRoute
@ -327,6 +343,7 @@ class HomeViewModel @Inject constructor(
hasActiveChallenge = challengeJob.await()
hasUpcomingDatePlan = dateJob.await()
hasUnlockedCapsule = capsuleJob.await()
hasPendingDateReflection = reflectionJob.await()
}
}
@ -349,6 +366,7 @@ class HomeViewModel @Inject constructor(
hasActiveChallenge = hasActiveChallenge,
hasUpcomingDatePlan = hasUpcomingDatePlan,
hasUnlockedCapsule = hasUnlockedCapsule,
hasPendingDateReflection = hasPendingDateReflection,
showOutcomeBaselineDialog = showBaselineDialog,
showOutcomeFollowUpDialog = followUpDay != null,
outcomeFollowUpDay = followUpDay,
@ -619,6 +637,7 @@ class HomeViewModel @Inject constructor(
weeklyRecapReady = weeklyRecapReady,
capsuleUnlocked = hasUnlockedCapsule(),
dateReminder = hasUpcomingDate(),
dateReflectionPending = hasPendingDateReflection,
suggestedPackAvailable = categories.isNotEmpty(),
exploreGamesAvailable = categories.isNotEmpty()
)
@ -759,6 +778,16 @@ class HomeViewModel @Inject constructor(
tone = HomeActionTone.Ritual
)
Priority.DATE_REFLECTION_PENDING -> HomeAction(
eyebrow = "Date replay",
title = partnerName?.let { "Reflect on your date with $it 💭" }
?: "Reflect on your date 💭",
body = "Capture what the night meant to you. You'll reveal your reflections together when you're both ready.",
cta = "Add your reflection",
target = HomeActionTarget.DateMemories,
tone = HomeActionTone.Reflection
)
Priority.SUGGESTED_PACK -> categories.firstOrNull()?.let { category ->
HomeAction(
eyebrow = "Suggested pack",
@ -845,11 +874,20 @@ class HomeViewModel @Inject constructor(
)
}
if (hasPendingDateReflection) {
actions += PendingActionCard(
title = "Reflect on your date",
subtitle = "Capture the night, then reveal together.",
priority = 6,
target = HomeActionTarget.DateMemories
)
}
if (hasUnlockedCapsule()) {
actions += PendingActionCard(
title = "Capsule unlocked",
subtitle = "A saved memory is ready to open together.",
priority = 6,
priority = 7,
target = HomeActionTarget.MemoryCapsule
)
}