From a500b866213fff07c0132ed4aed222b1ab604bbf Mon Sep 17 00:00:00 2001 From: null Date: Fri, 19 Jun 2026 22:46:07 -0500 Subject: [PATCH] chore: update UI copy to match retention tone guidelines (batch v1.0.9) --- .../app/closer/domain/model/MemoryCapsule.kt | 140 ++++++++++++++++++ .../app/closer/ui/brand/CloserBrandCopy.kt | 3 +- .../components/QuestionHelpExpandable.kt | 2 +- .../app/closer/ui/settings/PrivacyScreen.kt | 2 +- 4 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/app/closer/domain/model/MemoryCapsule.kt diff --git a/app/src/main/java/app/closer/domain/model/MemoryCapsule.kt b/app/src/main/java/app/closer/domain/model/MemoryCapsule.kt new file mode 100644 index 00000000..d3ce60ad --- /dev/null +++ b/app/src/main/java/app/closer/domain/model/MemoryCapsule.kt @@ -0,0 +1,140 @@ +package app.closer.domain.model + +import java.time.LocalDate + +/** + * A saved relationship moment visible only to couple members. + * + * Memory capsules are created from date ideas, reveals, weekly recaps, or manual entries. + * Notes are stored encrypted (E2EE). Photos are stored in Firebase Storage and visible only + * to couple members. Titles and tags are auto-generated from safe context metadata — never + * from decrypted answer text. + * + * @property id Firestore document ID or local ID. + * @property coupleId The couple that owns this memory. + * @property authorId User who created the memory. + * @property title User-set or auto-generated display title. + * @property date Calendar date associated with the memory. + * @property category Category key for grouping/filtering (e.g., "date", "reveal", "challenge", "recap", "manual"). + * @property noteCiphertext Optional user-written note, encrypted. Never plaintext. + * @property photoStoragePath Optional Firebase Storage path for a photo visible only to couple members. + * @property tags Auto-generated tags from context (category, event type, date). + * @property source What produced this memory. + * @property sourceRefId Optional reference to the originating event (date plan ID, question ID, etc.). + * @property createdAt Unix timestamp of creation. + * @property updatedAt Unix timestamp of last update. + */ +data class MemoryCapsule( + val id: String = "", + val coupleId: String = "", + val authorId: String = "", + val title: String = "", + val date: LocalDate = LocalDate.now(), + val category: String = "", + val noteCiphertext: String? = null, + val photoStoragePath: String? = null, + val tags: List = emptyList(), + val source: MemoryCapsuleSource = MemoryCapsuleSource.MANUAL, + val sourceRefId: String? = null, + val createdAt: Long = 0L, + val updatedAt: Long = 0L +) + +/** + * Origin of a memory capsule. + */ +enum class MemoryCapsuleSource { + DATE_IDEA, + REVEAL, + MANUAL, + WEEKLY_RECAP, + CHALLENGE; + + fun toFirestoreValue(): String = name.lowercase() + + companion object { + fun fromFirestoreValue(value: String): MemoryCapsuleSource = when (value.lowercase()) { + "date_idea", "date" -> DATE_IDEA + "reveal" -> REVEAL + "manual" -> MANUAL + "weekly_recap", "recap" -> WEEKLY_RECAP + "challenge" -> CHALLENGE + else -> MANUAL + } + } +} + +/** + * A saved date idea ready to become a memory after the date happens. + * + * @property dateIdeaId Reference to the saved date idea. + * @property title Date idea title. + * @property category Date idea category. + * @property scheduledDate When the date is planned. + */ +data class MemoryDateIdeaEvent( + val dateIdeaId: String, + val title: String = "", + val category: String = "", + val scheduledDate: LocalDate? = null +) + +/** + * A reveal ready to become a memory when both partners agree to save it. + * + * No decrypted answer text is carried here — only safe metadata. + * + * @property questionId Reference to the answered question. + * @property categoryId Question category. + * @property revealedDate Date the reveal occurred. + */ +data class MemoryRevealEvent( + val questionId: String, + val categoryId: String? = null, + val revealedDate: LocalDate +) + +/** + * A weekly recap ready to become a memory. + * + * @property recapId Reference to the recap document. + * @property weekStart Start of the recap week. + * @property weekEnd End of the recap week. + * @property favoriteCategory Favorite category ID from the recap. + */ +data class MemoryRecapEvent( + val recapId: String, + val weekStart: LocalDate, + val weekEnd: LocalDate, + val favoriteCategory: String? = null +) + +/** + * A completed challenge ready to become a memory. + * + * @property challengeId Reference to the challenge. + * @property challengeCategory Category ID of the challenge. + * @property completedDate Date the challenge was completed. + */ +data class MemoryChallengeEvent( + val challengeId: String, + val challengeCategory: String? = null, + val completedDate: LocalDate +) + +/** + * Raw manual input for a memory capsule. + * + * @property title User-supplied title. + * @property date Date associated with the memory. + * @property category Category key. + * @property noteCiphertext Encrypted user note. + * @property photoStoragePath Optional photo path. + */ +data class MemoryManualInput( + val title: String, + val date: LocalDate, + val category: String, + val noteCiphertext: String? = null, + val photoStoragePath: String? = null +) diff --git a/app/src/main/java/app/closer/ui/brand/CloserBrandCopy.kt b/app/src/main/java/app/closer/ui/brand/CloserBrandCopy.kt index d5ce2ddd..26ace5a9 100644 --- a/app/src/main/java/app/closer/ui/brand/CloserBrandCopy.kt +++ b/app/src/main/java/app/closer/ui/brand/CloserBrandCopy.kt @@ -9,8 +9,7 @@ object CloserBrandCopy { "No audience. No public feed. Just the two of you.", "Private by design.", "A private space for two.", - "Not even Closer can read your answers.", - "End to end encrypted private responses.", + "Encrypted answers are designed so Closer cannot read them.", "Built for trust, not tracking." ) } diff --git a/app/src/main/java/app/closer/ui/questions/components/QuestionHelpExpandable.kt b/app/src/main/java/app/closer/ui/questions/components/QuestionHelpExpandable.kt index be455a95..2a1374cb 100644 --- a/app/src/main/java/app/closer/ui/questions/components/QuestionHelpExpandable.kt +++ b/app/src/main/java/app/closer/ui/questions/components/QuestionHelpExpandable.kt @@ -105,7 +105,7 @@ private fun helpText(question: Question): String { "values" in question.tags -> " It also helps you align on what matters most to each of you." "memories" in question.tags -> " Revisiting shared memories reinforces your bond." "dreams" in question.tags -> " Talking about dreams reminds you that you're building a future together." - "fun" in question.tags -> " A little lightness goes a long way in keeping your connection alive." + "fun" in question.tags -> " A little lightness makes it easier to be yourselves together." else -> "" } return depthNote + tagNote diff --git a/app/src/main/java/app/closer/ui/settings/PrivacyScreen.kt b/app/src/main/java/app/closer/ui/settings/PrivacyScreen.kt index a7b55037..b7a7f50d 100644 --- a/app/src/main/java/app/closer/ui/settings/PrivacyScreen.kt +++ b/app/src/main/java/app/closer/ui/settings/PrivacyScreen.kt @@ -149,7 +149,7 @@ fun PrivacyScreen( Column(verticalArrangement = Arrangement.spacedBy(0.dp)) { PrivacyRow( title = "Answers before your partner answers", - body = "Your partner cannot see what you said until they've answered too. No peeking." + body = "In the app, your answer stays hidden until both of you have answered." ) Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 0.5.dp) PrivacyRow(