From d135b306aa256c3c4bbd70060bcd467276dd0e0f Mon Sep 17 00:00:00 2001 From: null Date: Wed, 17 Jun 2026 22:31:34 -0500 Subject: [PATCH] feat: add CategoryGlyph component, DesireSync polish, UI refinements across screens --- app/src/main/java/app/closer/MainActivity.kt | 2 +- .../closer/ui/answers/AnswerHistoryScreen.kt | 85 ++++--- .../closer/ui/auth/ForgotPasswordScreen.kt | 8 +- .../app/closer/ui/components/CategoryGlyph.kt | 239 ++++++++++++++++++ .../closer/ui/desiresync/DesireSyncScreen.kt | 39 ++- .../java/app/closer/ui/home/HomeScreen.kt | 7 + .../app/closer/ui/howwell/HowWellScreen.kt | 50 ++-- .../closer/ui/pairing/InviteConfirmScreen.kt | 10 +- .../java/app/closer/ui/play/PlayHubScreen.kt | 58 +++-- .../ui/questions/QuestionCategoryScreen.kt | 50 ++-- .../ui/questions/QuestionPackLibraryScreen.kt | 9 + .../closer/ui/wheel/CategoryPickerScreen.kt | 24 +- .../closer/ui/wheel/WheelCompleteScreen.kt | 15 +- 13 files changed, 469 insertions(+), 127 deletions(-) create mode 100644 app/src/main/java/app/closer/ui/components/CategoryGlyph.kt diff --git a/app/src/main/java/app/closer/MainActivity.kt b/app/src/main/java/app/closer/MainActivity.kt index a2482440..f3232d78 100644 --- a/app/src/main/java/app/closer/MainActivity.kt +++ b/app/src/main/java/app/closer/MainActivity.kt @@ -21,7 +21,7 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - AppNavigation(startDestination = app.closer.core.navigation.AppRoute.PLAY) + AppNavigation() } } } diff --git a/app/src/main/java/app/closer/ui/answers/AnswerHistoryScreen.kt b/app/src/main/java/app/closer/ui/answers/AnswerHistoryScreen.kt index 69b68c79..20fc95ad 100644 --- a/app/src/main/java/app/closer/ui/answers/AnswerHistoryScreen.kt +++ b/app/src/main/java/app/closer/ui/answers/AnswerHistoryScreen.kt @@ -4,6 +4,8 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -12,6 +14,7 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape @@ -30,6 +33,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush @@ -41,6 +45,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import app.closer.core.navigation.AppRoute import app.closer.domain.model.LocalAnswer +import app.closer.ui.components.CategoryGlyph import app.closer.ui.components.EmptyState import app.closer.ui.questions.displayCategoryName @@ -157,6 +162,7 @@ private fun AnswerHistoryContent( } +@OptIn(ExperimentalLayoutApi::class) @Composable private fun AnswerHistoryCard( answer: LocalAnswer, @@ -170,47 +176,62 @@ private fun AnswerHistoryCard( colors = CardDefaults.cardColors(containerColor = Color.White), elevation = CardDefaults.cardElevation(defaultElevation = 6.dp) ) { - Column( + Row( modifier = Modifier.padding(17.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.Top ) { - Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { - HistoryPill(if (answer.isRevealed) "Revealed" else "Private") - HistoryPill(answer.category.displayCategoryName()) - } - Text( - text = answer.questionText, - style = MaterialTheme.typography.titleMedium, - color = Color(0xFF261D2E), - fontWeight = FontWeight.SemiBold, - maxLines = 2, - overflow = TextOverflow.Ellipsis + CategoryGlyph( + categoryId = answer.category, + modifier = Modifier.size(46.dp), + size = 46.dp, + iconSize = 22.dp ) - Text( - text = if (answer.isRevealed) answer.revealSummary() else "Saved privately. Tap to reveal.", - style = MaterialTheme.typography.bodyMedium, - color = Color(0xFF5A5060), - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(12.dp) ) { + FlowRow( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + HistoryPill(if (answer.isRevealed) "Revealed" else "Private") + HistoryPill(answer.category.displayCategoryName()) + } Text( - text = if (answer.isRevealed) "Opened" else "Private", - style = MaterialTheme.typography.labelMedium, - color = Color(0xFF56306F), - fontWeight = FontWeight.SemiBold + text = answer.questionText, + style = MaterialTheme.typography.titleMedium, + color = Color(0xFF261D2E), + fontWeight = FontWeight.SemiBold, + maxLines = 2, + overflow = TextOverflow.Ellipsis ) - TextButton( - onClick = onDelete, - modifier = Modifier.heightIn(min = 48.dp) + Text( + text = if (answer.isRevealed) answer.revealSummary() else "Saved privately. Tap to reveal.", + style = MaterialTheme.typography.bodyMedium, + color = Color(0xFF5A5060), + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween ) { Text( - text = "Remove", - color = Color(0xFF8D2D35) + text = if (answer.isRevealed) "Opened" else "Private", + style = MaterialTheme.typography.labelMedium, + color = Color(0xFF56306F), + fontWeight = FontWeight.SemiBold ) + TextButton( + onClick = onDelete, + modifier = Modifier.heightIn(min = 48.dp) + ) { + Text( + text = "Remove", + color = Color(0xFF8D2D35) + ) + } } } } diff --git a/app/src/main/java/app/closer/ui/auth/ForgotPasswordScreen.kt b/app/src/main/java/app/closer/ui/auth/ForgotPasswordScreen.kt index e96fadfd..2826edf6 100644 --- a/app/src/main/java/app/closer/ui/auth/ForgotPasswordScreen.kt +++ b/app/src/main/java/app/closer/ui/auth/ForgotPasswordScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Check import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator @@ -47,6 +48,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import app.closer.core.navigation.AppRoute +import app.closer.ui.components.StatusGlyph @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -97,7 +99,11 @@ fun ForgotPasswordScreen( if (state.sent) { Spacer(Modifier.height(48.dp)) - Text("✓", style = MaterialTheme.typography.displayMedium, color = AuthPrimaryDeep) + StatusGlyph( + icon = Icons.Filled.Check, + tint = AuthPrimaryDeep, + container = AuthPrimary.copy(alpha = 0.16f) + ) Spacer(Modifier.height(16.dp)) Text( "Reset email sent", diff --git a/app/src/main/java/app/closer/ui/components/CategoryGlyph.kt b/app/src/main/java/app/closer/ui/components/CategoryGlyph.kt new file mode 100644 index 00000000..20092a3e --- /dev/null +++ b/app/src/main/java/app/closer/ui/components/CategoryGlyph.kt @@ -0,0 +1,239 @@ +package app.closer.ui.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.Chat +import androidx.compose.material.icons.filled.AttachMoney +import androidx.compose.material.icons.filled.CalendarToday +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material.icons.filled.FavoriteBorder +import androidx.compose.material.icons.filled.Home +import androidx.compose.material.icons.filled.Lock +import androidx.compose.material.icons.filled.People +import androidx.compose.material.icons.filled.Person +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material.icons.filled.Psychology +import androidx.compose.material.icons.filled.QuestionAnswer +import androidx.compose.material.icons.filled.Shield +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.filled.Sync +import androidx.compose.material.icons.filled.Timeline +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.Warning +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import app.closer.ui.theme.CloserPalette + +data class GlyphStyle( + val icon: ImageVector, + val tint: Color, + val container: Color +) + +@Composable +fun CategoryGlyph( + categoryId: String, + modifier: Modifier = Modifier, + iconName: String? = null, + locked: Boolean = false, + size: Dp = 48.dp, + iconSize: Dp = 23.dp +) { + val style = categoryGlyphStyle(categoryId = categoryId, iconName = iconName, locked = locked) + + Surface( + modifier = modifier.size(size), + shape = RoundedCornerShape((size.value * 0.36f).dp), + color = style.container + ) { + Box(contentAlignment = Alignment.Center) { + Icon( + imageVector = style.icon, + contentDescription = null, + tint = style.tint, + modifier = Modifier.size(iconSize) + ) + } + } +} + +@Composable +fun StatusGlyph( + icon: ImageVector, + modifier: Modifier = Modifier, + tint: Color = CloserPalette.PurpleDeep, + container: Color = CloserPalette.PurpleMist, + size: Dp = 72.dp, + iconSize: Dp = 34.dp, + shadowElevation: Dp = 0.dp +) { + Surface( + modifier = modifier.size(size), + shape = RoundedCornerShape((size.value * 0.34f).dp), + color = container, + shadowElevation = shadowElevation + ) { + Box(contentAlignment = Alignment.Center) { + Icon( + imageVector = icon, + contentDescription = null, + tint = tint, + modifier = Modifier.size(iconSize) + ) + } + } +} + +@Composable +fun ResultGlyph( + isPositive: Boolean, + modifier: Modifier = Modifier, + isClose: Boolean = false, + size: Dp = 32.dp +) { + val icon = when { + isPositive -> Icons.Filled.Check + isClose -> Icons.Filled.Timeline + else -> Icons.Filled.Close + } + val tint = when { + isPositive -> CloserPalette.Evergreen + isClose -> CloserPalette.Gold + else -> CloserPalette.Danger + } + val container = when { + isPositive -> CloserPalette.Evergreen.copy(alpha = 0.12f) + isClose -> CloserPalette.Gold.copy(alpha = 0.12f) + else -> CloserPalette.Danger.copy(alpha = 0.12f) + } + + StatusGlyph( + icon = icon, + modifier = modifier, + tint = tint, + container = container, + size = size, + iconSize = (size.value * 0.58f).dp + ) +} + +@Composable +fun categoryGlyphStyle( + categoryId: String, + iconName: String? = null, + locked: Boolean = false +): GlyphStyle { + if (locked) { + return GlyphStyle( + icon = Icons.Filled.Lock, + tint = MaterialTheme.colorScheme.outline, + container = CloserPalette.PurpleMist + ) + } + + val key = (iconName ?: categoryId).lowercase().trim() + return when (key) { + "communication", "chat", "question", "questions" -> GlyphStyle( + icon = Icons.AutoMirrored.Filled.Chat, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist + ) + "emotional_intimacy", "intimacy", "heart" -> GlyphStyle( + icon = Icons.Filled.Favorite, + tint = CloserPalette.PinkAccentDeep, + container = CloserPalette.PinkMist + ) + "physical_intimacy", "sex_and_desire", "sexual_preferences", "desire", "sex" -> GlyphStyle( + icon = Icons.Filled.FavoriteBorder, + tint = CloserPalette.Romantic, + container = CloserPalette.Romantic.copy(alpha = 0.12f) + ) + "trust", "rebuilding_trust", "privacy" -> GlyphStyle( + icon = Icons.Filled.Shield, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleGlow + ) + "conflict", "conflict_repair", "repair" -> GlyphStyle( + icon = Icons.Filled.Sync, + tint = CloserPalette.PurpleRich, + container = CloserPalette.PurpleMist + ) + "future", "timeline" -> GlyphStyle( + icon = Icons.Filled.Timeline, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleSoft + ) + "money", "payments" -> GlyphStyle( + icon = Icons.Filled.AttachMoney, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist + ) + "home_life", "home" -> GlyphStyle( + icon = Icons.Filled.Home, + tint = CloserPalette.PurpleRich, + container = CloserPalette.PurpleGlow + ) + "gratitude", "star" -> GlyphStyle( + icon = Icons.Filled.Star, + tint = CloserPalette.PinkAccentDeep, + container = CloserPalette.PinkMist + ) + "parenting", "family", "people" -> GlyphStyle( + icon = Icons.Filled.People, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleSoft + ) + "date_night", "date", "calendar" -> GlyphStyle( + icon = Icons.Filled.CalendarToday, + tint = CloserPalette.PinkAccentDeep, + container = CloserPalette.PinkMist + ) + "fun", "play" -> GlyphStyle( + icon = Icons.Filled.PlayArrow, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleGlow + ) + "stress", "difficult_conversations", "boundaries" -> GlyphStyle( + icon = Icons.Filled.Warning, + tint = CloserPalette.Danger, + container = CloserPalette.Danger.copy(alpha = 0.10f) + ) + "values", "marriage" -> GlyphStyle( + icon = Icons.Filled.QuestionAnswer, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist + ) + "profile", "person" -> GlyphStyle( + icon = Icons.Filled.Person, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist + ) + "reveal", "visibility" -> GlyphStyle( + icon = Icons.Filled.Visibility, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleGlow + ) + "predict", "psychology" -> GlyphStyle( + icon = Icons.Filled.Psychology, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleGlow + ) + else -> GlyphStyle( + icon = Icons.Filled.Star, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist + ) + } +} diff --git a/app/src/main/java/app/closer/ui/desiresync/DesireSyncScreen.kt b/app/src/main/java/app/closer/ui/desiresync/DesireSyncScreen.kt index 1dedad5f..b6ac6ec9 100644 --- a/app/src/main/java/app/closer/ui/desiresync/DesireSyncScreen.kt +++ b/app/src/main/java/app/closer/ui/desiresync/DesireSyncScreen.kt @@ -20,6 +20,11 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material.icons.filled.FavoriteBorder +import androidx.compose.material.icons.filled.Sync +import androidx.compose.material.icons.filled.Visibility import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card @@ -41,7 +46,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -49,6 +53,7 @@ import app.closer.core.navigation.AppRoute import app.closer.domain.model.ChoiceAnswerConfigImpl import app.closer.domain.model.Question import app.closer.domain.repository.QuestionRepository +import app.closer.ui.components.StatusGlyph import app.closer.ui.theme.CloserPalette import app.closer.ui.theme.closerBackgroundBrush import dagger.hilt.android.lifecycle.HiltViewModel @@ -305,10 +310,10 @@ private fun DSIntroScreen(playerNumber: Int, total: Int, onReady: () -> Unit) { verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text( - text = if (playerNumber == 1) "🔥" else "💜", - fontSize = 56.sp, - textAlign = TextAlign.Center + StatusGlyph( + icon = if (playerNumber == 1) Icons.Filled.FavoriteBorder else Icons.Filled.Visibility, + tint = CloserPalette.Romantic, + container = CloserPalette.Romantic.copy(alpha = 0.12f) ) Spacer(Modifier.height(20.dp)) Surface(shape = RoundedCornerShape(999.dp), color = CloserPalette.Romantic.copy(alpha = 0.14f)) { @@ -358,7 +363,11 @@ private fun DSHandoffScreen(onReady: () -> Unit) { verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text("🤝", fontSize = 56.sp, textAlign = TextAlign.Center) + StatusGlyph( + icon = Icons.Filled.Sync, + tint = CloserPalette.Romantic, + container = CloserPalette.Romantic.copy(alpha = 0.12f) + ) Spacer(Modifier.height(20.dp)) Text( text = "Pass the phone!", @@ -510,10 +519,12 @@ private fun DSRevealScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(10.dp) ) { - Text( - text = if (matches.isEmpty()) "🤍" else "🔥", - fontSize = 56.sp, - textAlign = TextAlign.Center + StatusGlyph( + icon = if (matches.isEmpty()) Icons.Filled.FavoriteBorder else Icons.Filled.Favorite, + tint = CloserPalette.Romantic, + container = CloserPalette.Romantic.copy(alpha = 0.12f), + size = 82.dp, + iconSize = 40.dp ) Text( text = if (matches.isEmpty()) "Nothing in common this round" else "${matches.size} shared desire${if (matches.size != 1) "s" else ""}", @@ -599,7 +610,13 @@ private fun DesireMatchCard(match: DesireMatch) { horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically ) { - Text("❤️", fontSize = 20.sp) + StatusGlyph( + icon = Icons.Filled.Favorite, + tint = CloserPalette.Romantic, + container = CloserPalette.Romantic.copy(alpha = 0.12f), + size = 34.dp, + iconSize = 18.dp + ) Text( text = match.femaleQ.text, style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Medium), diff --git a/app/src/main/java/app/closer/ui/home/HomeScreen.kt b/app/src/main/java/app/closer/ui/home/HomeScreen.kt index a042e6e2..c8af2fae 100644 --- a/app/src/main/java/app/closer/ui/home/HomeScreen.kt +++ b/app/src/main/java/app/closer/ui/home/HomeScreen.kt @@ -43,6 +43,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import app.closer.core.navigation.AppRoute import app.closer.domain.model.Question import app.closer.domain.model.QuestionCategory +import app.closer.ui.components.CategoryGlyph import app.closer.ui.questions.displayCategoryName @Composable @@ -566,6 +567,12 @@ private fun CategoryMiniCard( modifier = Modifier.padding(15.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { + CategoryGlyph( + categoryId = item.category.id, + iconName = item.category.iconName, + size = 42.dp, + iconSize = 20.dp + ) Text( text = item.category.displayName.ifBlank { item.category.id.displayCategoryName() }, style = MaterialTheme.typography.titleSmall, diff --git a/app/src/main/java/app/closer/ui/howwell/HowWellScreen.kt b/app/src/main/java/app/closer/ui/howwell/HowWellScreen.kt index 390deb8e..095fbb44 100644 --- a/app/src/main/java/app/closer/ui/howwell/HowWellScreen.kt +++ b/app/src/main/java/app/closer/ui/howwell/HowWellScreen.kt @@ -19,6 +19,11 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Person +import androidx.compose.material.icons.filled.Psychology +import androidx.compose.material.icons.filled.Sync +import androidx.compose.material.icons.filled.Timeline import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card @@ -40,7 +45,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -52,6 +56,8 @@ import app.closer.domain.model.Question import app.closer.domain.model.ScaleAnswerConfigImpl import app.closer.domain.model.ThisOrThatAnswerConfigImpl import app.closer.domain.repository.QuestionRepository +import app.closer.ui.components.ResultGlyph +import app.closer.ui.components.StatusGlyph import app.closer.ui.theme.CloserPalette import app.closer.ui.theme.closerBackgroundBrush import dagger.hilt.android.lifecycle.HiltViewModel @@ -306,7 +312,11 @@ private fun PlayerIntroScreen(playerNumber: Int, total: Int, onReady: () -> Unit verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text(text = if (playerNumber == 1) "👤" else "🔮", fontSize = 56.sp, textAlign = TextAlign.Center) + StatusGlyph( + icon = if (playerNumber == 1) Icons.Filled.Person else Icons.Filled.Psychology, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist + ) Spacer(Modifier.height(20.dp)) Surface(shape = RoundedCornerShape(999.dp), color = CloserPalette.PurpleMist) { Text( @@ -358,7 +368,11 @@ private fun HandoffScreen(onReady: () -> Unit) { verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text("🎉", fontSize = 56.sp, textAlign = TextAlign.Center) + StatusGlyph( + icon = Icons.Filled.Sync, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist + ) Spacer(Modifier.height(20.dp)) Text( text = "Pass the phone!", @@ -566,10 +580,10 @@ private fun RevealScreen( horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically ) { - Text( - text = if (result.isMatch) "✓" else if (result.isClose) "≈" else "✗", - fontSize = 28.sp, - color = accentColor + ResultGlyph( + isPositive = result.isMatch, + isClose = result.isClose, + size = 38.dp ) Text( text = if (result.isMatch) "Match!" else if (result.isClose) "So close!" else "Not quite", @@ -678,7 +692,13 @@ private fun CompleteScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(10.dp) ) { - Text("🎯", fontSize = 56.sp, textAlign = TextAlign.Center) + StatusGlyph( + icon = Icons.Filled.Timeline, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist, + size = 82.dp, + iconSize = 40.dp + ) Text( text = "$score / $total", style = MaterialTheme.typography.displaySmall.copy(fontWeight = FontWeight.Bold), @@ -743,10 +763,10 @@ private fun BreakdownRow(result: HowWellResult) { horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically ) { - Text( - text = if (result.isMatch) "✓" else if (result.isClose) "≈" else "✗", - fontSize = 18.sp, - color = if (result.isMatch) matchColor else if (result.isClose) closeColor else missColor + ResultGlyph( + isPositive = result.isMatch, + isClose = result.isClose, + size = 28.dp ) Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) { Text( @@ -910,9 +930,9 @@ private fun ScaleInput( // ── Helpers ─────────────────────────────────────────────────────────────────── private fun scoreLabel(score: Int, total: Int): String = when { - score == total -> "Mind reader! 🤯" - score >= total * 0.8 -> "You really know each other 💜" + score == total -> "Perfect read" + score >= total * 0.8 -> "You really know each other" score >= total * 0.6 -> "Pretty good!" score >= total * 0.4 -> "Getting there!" - else -> "Room to grow 🌱" + else -> "Room to grow" } diff --git a/app/src/main/java/app/closer/ui/pairing/InviteConfirmScreen.kt b/app/src/main/java/app/closer/ui/pairing/InviteConfirmScreen.kt index 7f3a1612..bf2090a5 100644 --- a/app/src/main/java/app/closer/ui/pairing/InviteConfirmScreen.kt +++ b/app/src/main/java/app/closer/ui/pairing/InviteConfirmScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator @@ -44,6 +45,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import app.closer.core.navigation.AppRoute +import app.closer.ui.components.StatusGlyph import app.closer.ui.settings.SettingsBackgroundBrush import app.closer.ui.settings.SettingsInk import app.closer.ui.settings.SettingsMuted @@ -109,10 +111,10 @@ fun InviteConfirmScreen( } else { Spacer(Modifier.height(24.dp)) - Text( - "♡", - style = MaterialTheme.typography.displayMedium, - color = SettingsPrimaryDeep + StatusGlyph( + icon = Icons.Filled.FavoriteBorder, + tint = SettingsPrimaryDeep, + container = SettingsSoft ) Spacer(Modifier.height(16.dp)) diff --git a/app/src/main/java/app/closer/ui/play/PlayHubScreen.kt b/app/src/main/java/app/closer/ui/play/PlayHubScreen.kt index f8573901..926227e6 100644 --- a/app/src/main/java/app/closer/ui/play/PlayHubScreen.kt +++ b/app/src/main/java/app/closer/ui/play/PlayHubScreen.kt @@ -19,6 +19,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowForward import androidx.compose.material.icons.filled.Done import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Home +import androidx.compose.material.icons.filled.Lock import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.filled.Star import androidx.compose.material3.Button @@ -39,6 +40,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import app.closer.core.navigation.AppRoute +import app.closer.ui.components.CategoryGlyph import app.closer.ui.theme.CloserPalette import app.closer.ui.theme.closerBackgroundBrush import app.closer.ui.theme.closerBrandGlyphBrush @@ -261,15 +263,12 @@ private fun DesireSyncCard( horizontalArrangement = Arrangement.spacedBy(14.dp), verticalAlignment = Alignment.CenterVertically ) { - Surface( - shape = RoundedCornerShape(18.dp), - color = CloserPalette.Romantic.copy(alpha = 0.12f), - modifier = Modifier.size(52.dp) - ) { - Box(contentAlignment = Alignment.Center) { - Text(text = "🔥", style = MaterialTheme.typography.titleMedium) - } - } + CategoryGlyph( + categoryId = "sex_and_desire", + modifier = Modifier.size(52.dp), + size = 52.dp, + iconSize = 25.dp + ) Column( modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp) @@ -290,13 +289,24 @@ private fun DesireSyncCard( shape = RoundedCornerShape(999.dp), color = CloserPalette.Romantic.copy(alpha = 0.12f) ) { - Text( - text = "🔒 Premium", + Row( modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp), - style = MaterialTheme.typography.labelSmall, - color = CloserPalette.Romantic, - fontWeight = FontWeight.SemiBold - ) + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Filled.Lock, + contentDescription = null, + tint = CloserPalette.Romantic, + modifier = Modifier.size(13.dp) + ) + Text( + text = "Premium", + style = MaterialTheme.typography.labelSmall, + color = CloserPalette.Romantic, + fontWeight = FontWeight.SemiBold + ) + } } } Text( @@ -335,18 +345,12 @@ private fun HowWellCard( horizontalArrangement = Arrangement.spacedBy(14.dp), verticalAlignment = Alignment.CenterVertically ) { - Surface( - shape = RoundedCornerShape(18.dp), - color = CloserPalette.Romantic.copy(alpha = 0.12f), - modifier = Modifier.size(52.dp) - ) { - Box(contentAlignment = Alignment.Center) { - Text( - text = "💜", - style = MaterialTheme.typography.titleMedium - ) - } - } + CategoryGlyph( + categoryId = "predict", + modifier = Modifier.size(52.dp), + size = 52.dp, + iconSize = 25.dp + ) Column( modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp) diff --git a/app/src/main/java/app/closer/ui/questions/QuestionCategoryScreen.kt b/app/src/main/java/app/closer/ui/questions/QuestionCategoryScreen.kt index 6deeb937..925f8f8f 100644 --- a/app/src/main/java/app/closer/ui/questions/QuestionCategoryScreen.kt +++ b/app/src/main/java/app/closer/ui/questions/QuestionCategoryScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -42,6 +43,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import app.closer.core.navigation.AppRoute import app.closer.domain.model.Question import app.closer.domain.model.QuestionCategory +import app.closer.ui.components.CategoryGlyph @Composable fun QuestionCategoryScreen( @@ -168,21 +170,39 @@ private fun CategoryHero( modifier = modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(12.dp) ) { - Text( - text = title, - style = MaterialTheme.typography.headlineLarge.copy(fontWeight = FontWeight.SemiBold), - color = Color(0xFF261D2E), - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - Text( - text = category?.description - ?: "Browse prompts for this kind of conversation.", - style = MaterialTheme.typography.bodyLarge, - color = Color(0xFF5A5060), - maxLines = 3, - overflow = TextOverflow.Ellipsis - ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(14.dp), + verticalAlignment = Alignment.Top + ) { + CategoryGlyph( + categoryId = category?.id ?: title, + iconName = category?.iconName, + modifier = Modifier.size(58.dp), + size = 58.dp, + iconSize = 28.dp + ) + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = title, + style = MaterialTheme.typography.headlineLarge.copy(fontWeight = FontWeight.SemiBold), + color = Color(0xFF261D2E), + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + Text( + text = category?.description + ?: "Browse prompts for this kind of conversation.", + style = MaterialTheme.typography.bodyLarge, + color = Color(0xFF5A5060), + maxLines = 3, + overflow = TextOverflow.Ellipsis + ) + } + } Row( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/app/closer/ui/questions/QuestionPackLibraryScreen.kt b/app/src/main/java/app/closer/ui/questions/QuestionPackLibraryScreen.kt index ee4b5ee6..e81451c1 100644 --- a/app/src/main/java/app/closer/ui/questions/QuestionPackLibraryScreen.kt +++ b/app/src/main/java/app/closer/ui/questions/QuestionPackLibraryScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -44,6 +45,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import app.closer.core.navigation.AppRoute import app.closer.domain.model.QuestionCategory +import app.closer.ui.components.CategoryGlyph private enum class PackFilter(val label: String) { ALL("All"), @@ -226,6 +228,13 @@ private fun QuestionPackCard( horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.Top ) { + CategoryGlyph( + categoryId = item.category.id, + iconName = item.category.iconName, + locked = item.isLocked, + modifier = Modifier.size(50.dp), + size = 50.dp + ) Column( modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(6.dp) diff --git a/app/src/main/java/app/closer/ui/wheel/CategoryPickerScreen.kt b/app/src/main/java/app/closer/ui/wheel/CategoryPickerScreen.kt index fc0dbda4..402542b3 100644 --- a/app/src/main/java/app/closer/ui/wheel/CategoryPickerScreen.kt +++ b/app/src/main/java/app/closer/ui/wheel/CategoryPickerScreen.kt @@ -17,9 +17,7 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.automirrored.filled.ArrowForward import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Lock import androidx.compose.material.icons.filled.PlayArrow -import androidx.compose.material.icons.filled.Star import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card @@ -41,6 +39,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import app.closer.core.navigation.AppRoute import app.closer.domain.model.QuestionCategory +import app.closer.ui.components.CategoryGlyph import app.closer.ui.questions.displayCategoryName import app.closer.ui.theme.CloserPalette import app.closer.ui.theme.closerBackgroundBrush @@ -257,20 +256,13 @@ private fun CategoryCard( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - Surface( - shape = RoundedCornerShape(18.dp), - color = if (item.isLocked) CloserPalette.PurpleMist else MaterialTheme.colorScheme.secondaryContainer, - modifier = Modifier.size(48.dp) - ) { - Box(contentAlignment = Alignment.Center) { - Icon( - imageVector = if (item.isLocked) Icons.Default.Lock else Icons.Filled.Star, - contentDescription = null, - tint = if (item.isLocked) MaterialTheme.colorScheme.outline else CloserPalette.PinkAccentDeep, - modifier = Modifier.size(22.dp) - ) - } - } + CategoryGlyph( + categoryId = item.category.id, + iconName = item.category.iconName, + locked = item.isLocked, + modifier = Modifier.size(48.dp), + size = 48.dp + ) Column( modifier = Modifier .weight(1f) diff --git a/app/src/main/java/app/closer/ui/wheel/WheelCompleteScreen.kt b/app/src/main/java/app/closer/ui/wheel/WheelCompleteScreen.kt index ed4a8263..0c40507b 100644 --- a/app/src/main/java/app/closer/ui/wheel/WheelCompleteScreen.kt +++ b/app/src/main/java/app/closer/ui/wheel/WheelCompleteScreen.kt @@ -21,6 +21,8 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card @@ -39,8 +41,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import app.closer.ui.components.StatusGlyph +import app.closer.ui.theme.CloserPalette @HiltViewModel class WheelCompleteViewModel @Inject constructor( @@ -120,10 +123,12 @@ private fun WheelCompleteContent( verticalArrangement = Arrangement.spacedBy(24.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Text( - text = "✓", - fontSize = 64.sp, - color = Color(0xFFB98AF4) + StatusGlyph( + icon = Icons.Filled.Check, + tint = CloserPalette.PurpleDeep, + container = CloserPalette.PurpleMist, + size = 82.dp, + iconSize = 40.dp ) Column(