Revert "feat(date-memories): add Home nudge for pending date reflection + priority engine (batch 3/8)"

This reverts commit 4ecb1560cb.
This commit is contained in:
null 2026-06-30 18:13:00 -05:00
parent c19e7ea711
commit 5905c2b2d0
4 changed files with 12 additions and 122 deletions

View File

@ -19,9 +19,8 @@ package app.closer.ui.home
* 9. Weekly recap ready
* 10. Capsule unlocked
* 11. Date reminder
* 12. Date reflection pending
* 13. Suggested pack
* 14. Explore games
* 12. Suggested pack
* 13. Explore games
*
* Rules:
* - Show one primary CTA.
@ -50,7 +49,6 @@ object HomePriorityEngine {
val weeklyRecapReady: Boolean = false,
val capsuleUnlocked: Boolean = false,
val dateReminder: Boolean = false,
val dateReflectionPending: Boolean = false,
val suggestedPackAvailable: Boolean = false,
val exploreGamesAvailable: Boolean = false
)
@ -70,9 +68,6 @@ object HomePriorityEngine {
WEEKLY_RECAP_READY,
CAPSULE_UNLOCKED,
DATE_REMINDER,
// You marked a date done but haven't reflected yet. Value action in the date band: an actionable
// shared-memory prompt, ranked above the daily-question closure card.
DATE_REFLECTION_PENDING,
// You already revealed today's question — a low-priority "keep the conversation going" closure card.
DAILY_QUESTION_REVEALED,
SUGGESTED_PACK,
@ -146,7 +141,6 @@ object HomePriorityEngine {
Priority.WEEKLY_RECAP_READY -> input.weeklyRecapReady
Priority.CAPSULE_UNLOCKED -> input.capsuleUnlocked
Priority.DATE_REMINDER -> input.dateReminder
Priority.DATE_REFLECTION_PENDING -> input.dateReflectionPending
Priority.SUGGESTED_PACK -> input.suggestedPackAvailable
Priority.EXPLORE_GAMES -> input.exploreGamesAvailable
}
@ -172,8 +166,7 @@ object HomePriorityEngine {
Priority.DAILY_QUESTION_AWAITING_PARTNER,
Priority.DAILY_QUESTION_REVEALED,
Priority.WEEKLY_RECAP_READY,
Priority.DATE_REMINDER,
Priority.DATE_REFLECTION_PENDING -> true
Priority.DATE_REMINDER -> true
else -> false
}
}

View File

@ -251,7 +251,6 @@ private fun HomeCallbacks.toActionHandler(onNavigate: (String) -> Unit): (HomeAc
HomeActionTarget.Challenge -> onNavigate(AppRoute.CONNECTION_CHALLENGES)
HomeActionTarget.DatePlan -> onNavigate(AppRoute.DATE_MATCHES)
HomeActionTarget.MemoryCapsule -> onNavigate(AppRoute.MEMORY_LANE)
HomeActionTarget.DateMemories -> onNavigate(AppRoute.DATE_MEMORIES)
}
}
@ -417,7 +416,6 @@ private fun homeActionGlyph(target: HomeActionTarget): Int = when (target) {
HomeActionTarget.Challenge -> R.drawable.glyph_connection_challenge
HomeActionTarget.DatePlan -> R.drawable.glyph_date_card_heart
HomeActionTarget.MemoryCapsule -> R.drawable.glyph_memory_capsule
HomeActionTarget.DateMemories -> R.drawable.glyph_date_replay
}
@Composable
@ -717,16 +715,6 @@ private fun PartnerQuickActionsSheet(
if (state.togetherSince > 0L) add("together since ${formatMonthYear(state.togetherSince)}")
}.joinToString(" · ")
}
// Living "today" status — reflects where the couple is in the daily ritual. Hidden when there's no
// question assigned (no misleading "still open").
val todayStatus = state.dailyQuestion?.let {
when (state.dailyQuestionState) {
DailyQuestionState.BOTH_ANSWERED, DailyQuestionState.REVEALED -> "You've both answered today 💜"
DailyQuestionState.PARTNER_ANSWERED_USER_PENDING -> "They answered — your turn"
DailyQuestionState.USER_ANSWERED_PARTNER_PENDING -> "Waiting on their answer"
DailyQuestionState.UNANSWERED -> "Tonight's question is still open"
}
}
val openPartnerPage = { onNavigate(AppRoute.PARTNER_HOME); onDismiss() }
ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState) {
@ -769,36 +757,26 @@ private fun PartnerQuickActionsSheet(
overflow = TextOverflow.Ellipsis
)
}
todayStatus?.let {
Text(
text = it,
style = MaterialTheme.typography.bodySmall.copy(fontWeight = FontWeight.Medium),
color = MaterialTheme.colorScheme.primary,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}
Divider(modifier = Modifier.padding(vertical = 4.dp), thickness = 0.5.dp)
PartnerSheetAction(R.drawable.glyph_heart, "Thinking of you", enabled = !state.isSendingNudge, onClick = onThinkingOfYou)
PartnerSheetAction(R.drawable.glyph_chat, "Message") { onNavigate(AppRoute.MESSAGES); onDismiss() }
PartnerSheetAction("💜", "Thinking of you", enabled = !state.isSendingNudge, onClick = onThinkingOfYou)
PartnerSheetAction("💬", "Message") { onNavigate(AppRoute.MESSAGES); onDismiss() }
PartnerSheetAction(
R.drawable.glyph_paired_cards,
"",
"Together",
trailing = state.unreadActivityCount.takeIf { it > 0 }?.let { if (it > 9) "9+" else "$it" }
) { onNavigate(AppRoute.ACTIVITY); onDismiss() }
PartnerSheetAction(R.drawable.glyph_memory_capsule, "Our memories") { onNavigate(AppRoute.MEMORY_LANE); onDismiss() }
PartnerSheetAction(R.drawable.glyph_settings, "Your relationship") { onNavigate(AppRoute.RELATIONSHIP_SETTINGS); onDismiss() }
PartnerSheetAction("⚙️", "Your relationship") { onNavigate(AppRoute.RELATIONSHIP_SETTINGS); onDismiss() }
}
}
}
@Composable
private fun PartnerSheetAction(
@DrawableRes iconRes: Int,
emoji: String,
label: String,
enabled: Boolean = true,
trailing: String? = null,
@ -813,12 +791,7 @@ private fun PartnerSheetAction(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
HomeGlyphIcon(
resId = iconRes,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(22.dp)
)
Text(text = emoji, style = MaterialTheme.typography.titleMedium)
Text(
text = label,
modifier = Modifier.weight(1f),

View File

@ -70,8 +70,7 @@ enum class HomeActionTarget {
Game,
Challenge,
DatePlan,
MemoryCapsule,
DateMemories
MemoryCapsule
}
enum class HomeActionTone {
@ -159,8 +158,6 @@ 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). */
@ -195,9 +192,7 @@ 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 dateMemoryDataSource: app.closer.data.remote.FirestoreDateMemoryDataSource,
private val dateReflectionDataSource: app.closer.data.remote.FirestoreDateReflectionDataSource
private val dailyQuestionResolver: app.closer.domain.usecase.DailyQuestionResolver
) : ViewModel() {
private val _uiState = MutableStateFlow(HomeUiState())
@ -294,7 +289,6 @@ 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 {
@ -326,16 +320,6 @@ 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
@ -343,7 +327,6 @@ class HomeViewModel @Inject constructor(
hasActiveChallenge = challengeJob.await()
hasUpcomingDatePlan = dateJob.await()
hasUnlockedCapsule = capsuleJob.await()
hasPendingDateReflection = reflectionJob.await()
}
}
@ -366,7 +349,6 @@ class HomeViewModel @Inject constructor(
hasActiveChallenge = hasActiveChallenge,
hasUpcomingDatePlan = hasUpcomingDatePlan,
hasUnlockedCapsule = hasUnlockedCapsule,
hasPendingDateReflection = hasPendingDateReflection,
showOutcomeBaselineDialog = showBaselineDialog,
showOutcomeFollowUpDialog = followUpDay != null,
outcomeFollowUpDay = followUpDay,
@ -637,7 +619,6 @@ class HomeViewModel @Inject constructor(
weeklyRecapReady = weeklyRecapReady,
capsuleUnlocked = hasUnlockedCapsule(),
dateReminder = hasUpcomingDate(),
dateReflectionPending = hasPendingDateReflection,
suggestedPackAvailable = categories.isNotEmpty(),
exploreGamesAvailable = categories.isNotEmpty()
)
@ -778,16 +759,6 @@ 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",
@ -874,20 +845,11 @@ 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 = 7,
priority = 6,
target = HomeActionTarget.MemoryCapsule
)
}

View File

@ -318,44 +318,6 @@ class HomePriorityEngineTest {
)
}
@Test
fun `date reflection pending is a value action that surfaces as a secondary card`() {
val input = Input(
isPaired = true,
dailyQuestionUnanswered = true,
dateReflectionPending = true,
suggestedPackAvailable = true,
exploreGamesAvailable = true
)
val output = HomePriorityEngine.compute(input)
// Daily question is the hero; the pending reflection rides along as a value-action card,
// while the generic browse items (pack/explore) are filtered out of the secondary band.
assertEquals(Priority.DAILY_QUESTION_UNANSWERED, output.primary?.priority)
assertEquals(
listOf(Priority.DATE_REFLECTION_PENDING),
output.secondary.map { it.priority }
)
}
@Test
fun `date reflection pending outranks the daily question closure card`() {
val input = Input(
isPaired = true,
dateReflectionPending = true,
dailyQuestionRevealed = true
)
val output = HomePriorityEngine.compute(input)
assertEquals(Priority.DATE_REFLECTION_PENDING, output.primary?.priority)
assertEquals(
listOf(Priority.DAILY_QUESTION_REVEALED),
output.secondary.map { it.priority }
)
}
@Test
fun `primary priority convenience returns pairing needed for default empty input`() {
assertEquals(Priority.PAIRING_NEEDED, HomePriorityEngine.primaryPriority(Input()))