refactor(theme): full dark mode pass — CloserPalette, Theme, Color, and all surface screens

This commit is contained in:
null 2026-06-23 13:56:27 -05:00
parent 7d3b47b3ba
commit fe1808b36c
16 changed files with 343 additions and 207 deletions

View File

@ -1,6 +1,5 @@
package app.closer.ui.components package app.closer.ui.components
import app.closer.ui.theme.CloserPalette
import app.closer.ui.theme.closerCardColor import app.closer.ui.theme.closerCardColor
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -134,7 +133,7 @@ fun CloserActionButton(
border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.34f)), border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.34f)),
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(
containerColor = containerColor ?: MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.42f), containerColor = containerColor ?: MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.42f),
contentColor = contentColor ?: CloserPalette.PurpleDeep contentColor = contentColor ?: MaterialTheme.colorScheme.onPrimaryContainer
) )
) { ) {
Text(label) Text(label)
@ -145,10 +144,10 @@ fun CloserActionButton(
modifier = modifier, modifier = modifier,
enabled = enabled, enabled = enabled,
shape = shape, shape = shape,
border = BorderStroke(1.dp, CloserPalette.Danger.copy(alpha = 0.38f)), border = BorderStroke(1.dp, MaterialTheme.colorScheme.error.copy(alpha = 0.38f)),
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(
containerColor = containerColor ?: CloserPalette.PinkMist, containerColor = containerColor ?: MaterialTheme.colorScheme.errorContainer.copy(alpha = 0.18f),
contentColor = contentColor ?: CloserPalette.Danger contentColor = contentColor ?: MaterialTheme.colorScheme.error
) )
) { ) {
Text(label) Text(label)
@ -161,7 +160,7 @@ fun CloserPill(
label: String, label: String,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
containerColor: Color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.55f), containerColor: Color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.55f),
contentColor: Color = CloserPalette.PurpleDeep contentColor: Color = MaterialTheme.colorScheme.onPrimaryContainer
) { ) {
Surface( Surface(
modifier = modifier, modifier = modifier,

View File

@ -17,6 +17,7 @@ import app.closer.ui.questions.displayCategoryName
import app.closer.ui.theme.CloserPalette import app.closer.ui.theme.CloserPalette
import app.closer.ui.theme.closerBackgroundBrush import app.closer.ui.theme.closerBackgroundBrush
import app.closer.ui.theme.closerCardColor import app.closer.ui.theme.closerCardColor
import app.closer.ui.theme.isCloserDarkTheme
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -473,6 +474,8 @@ private fun PartnerActivationCard(
onInvite: () -> Unit, onInvite: () -> Unit,
onAcceptInvite: () -> Unit onAcceptInvite: () -> Unit
) { ) {
val isDark = isCloserDarkTheme()
val inviteTone = HomeActionTone.Invite.actionColors()
CloserCard( CloserCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(CloserRadii.FeatureCard), shape = RoundedCornerShape(CloserRadii.FeatureCard),
@ -483,11 +486,19 @@ private fun PartnerActivationCard(
modifier = Modifier modifier = Modifier
.background( .background(
Brush.linearGradient( Brush.linearGradient(
if (isDark) {
listOf(
MaterialTheme.colorScheme.surface,
MaterialTheme.colorScheme.surfaceVariant,
MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.72f)
)
} else {
listOf( listOf(
MaterialTheme.colorScheme.surface, MaterialTheme.colorScheme.surface,
CloserPalette.PurpleSoft, CloserPalette.PurpleSoft,
CloserPalette.PinkMist.copy(alpha = 0.84f) CloserPalette.PinkMist.copy(alpha = 0.84f)
), )
},
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@ -513,13 +524,13 @@ private fun PartnerActivationCard(
Icon( Icon(
imageVector = Icons.Filled.Lock, imageVector = Icons.Filled.Lock,
contentDescription = null, contentDescription = null,
tint = CloserPalette.PurpleDeep, tint = inviteTone.deep,
modifier = Modifier.size(14.dp) modifier = Modifier.size(14.dp)
) )
Text( Text(
text = "Private invite", text = "Private invite",
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = CloserPalette.PurpleDeep, color = inviteTone.deep,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
maxLines = 1, maxLines = 1,
@ -550,7 +561,7 @@ private fun PartnerActivationCard(
Text( Text(
text = "Invite your partner to unlock shared reveals, games, streaks, and answers you can both respond to.", text = "Invite your partner to unlock shared reveals, games, streaks, and answers you can both respond to.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = Color(0xFF4D4354), color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 4, maxLines = 4,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
@ -570,8 +581,8 @@ private fun PartnerActivationCard(
label = "Invite partner", label = "Invite partner",
onClick = onInvite, onClick = onInvite,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
containerColor = CloserPalette.PurpleDeep, containerColor = inviteTone.accent,
contentColor = MaterialTheme.colorScheme.surface contentColor = inviteTone.onAccent
) )
CloserActionButton( CloserActionButton(
label = "Enter code", label = "Enter code",
@ -579,7 +590,7 @@ private fun PartnerActivationCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
style = CloserButtonStyle.Secondary, style = CloserButtonStyle.Secondary,
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.7f), containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.7f),
contentColor = CloserPalette.PurpleDeep contentColor = inviteTone.deep
) )
} }
} }
@ -591,6 +602,7 @@ private fun ActivationBenefitPill(
label: String, label: String,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val colors = HomeActionTone.Invite.actionColors()
Surface( Surface(
modifier = modifier, modifier = modifier,
shape = RoundedCornerShape(CloserRadii.Pill), shape = RoundedCornerShape(CloserRadii.Pill),
@ -602,7 +614,7 @@ private fun ActivationBenefitPill(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 9.dp, vertical = 7.dp), .padding(horizontal = 9.dp, vertical = 7.dp),
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = CloserPalette.PurpleDeep, color = colors.deep,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
maxLines = 1, maxLines = 1,
@ -624,6 +636,7 @@ private fun PrimaryHomeActionCard(
dailyQuestion: Question? dailyQuestion: Question?
) { ) {
val colors = action.tone.actionColors() val colors = action.tone.actionColors()
val isDark = isCloserDarkTheme()
// For daily-question actions, route the CTA through the explicit state handlers // For daily-question actions, route the CTA through the explicit state handlers
// so the same button label maps to the correct next step (answer, remind, // so the same button label maps to the correct next step (answer, remind,
@ -685,7 +698,19 @@ private fun PrimaryHomeActionCard(
modifier = Modifier modifier = Modifier
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(MaterialTheme.colorScheme.surface, colors.soft, CloserPalette.PinkMist.copy(alpha = 0.72f)), if (isDark) {
listOf(
MaterialTheme.colorScheme.surface,
MaterialTheme.colorScheme.surfaceVariant,
colors.soft.copy(alpha = 0.72f)
)
} else {
listOf(
MaterialTheme.colorScheme.surface,
colors.soft,
CloserPalette.PinkMist.copy(alpha = 0.72f)
)
},
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@ -748,7 +773,7 @@ private fun PrimaryHomeActionCard(
Text( Text(
text = bodyOverride, text = bodyOverride,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = Color(0xFF4D4354), color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 4, maxLines = 4,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
@ -813,7 +838,7 @@ private fun PulseMetric(
Text( Text(
text = value, text = value,
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.SemiBold), style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.SemiBold),
color = CloserPalette.PurpleDeep, color = MaterialTheme.colorScheme.primary,
maxLines = 1 maxLines = 1
) )
Text( Text(
@ -926,10 +951,15 @@ private fun SecondaryHomeActionCard(
@Composable @Composable
private fun MomentCueCard() { private fun MomentCueCard() {
val isDark = isCloserDarkTheme()
CloserCard( CloserCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(CloserRadii.Card), shape = RoundedCornerShape(CloserRadii.Card),
containerColor = CloserPalette.PinkMist.copy(alpha = 0.7f), containerColor = if (isDark) {
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.58f)
} else {
CloserPalette.PinkMist.copy(alpha = 0.7f)
},
elevation = CloserElevations.Flat elevation = CloserElevations.Flat
) { ) {
Column( Column(
@ -960,53 +990,89 @@ private data class HomeActionColors(
val soft: Color, val soft: Color,
val accent: Color, val accent: Color,
val deep: Color, val deep: Color,
val onAccent: Color = Color(0xFF24122F) val onAccent: Color
) )
@Composable @Composable
private fun HomeActionTone.actionColors(): HomeActionColors = private fun HomeActionTone.actionColors(): HomeActionColors {
when (this) { val scheme = MaterialTheme.colorScheme
if (isCloserDarkTheme()) {
return when (this) {
HomeActionTone.Daily,
HomeActionTone.Ritual,
HomeActionTone.Starter,
HomeActionTone.Pack -> HomeActionColors(
soft = scheme.secondaryContainer,
accent = scheme.secondary,
deep = scheme.secondary,
onAccent = scheme.onSecondary
)
HomeActionTone.Reflection -> HomeActionColors(
soft = scheme.tertiaryContainer,
accent = scheme.tertiary,
deep = scheme.tertiary,
onAccent = scheme.onTertiary
)
else -> HomeActionColors(
soft = scheme.primaryContainer,
accent = scheme.primary,
deep = scheme.primary,
onAccent = scheme.onPrimary
)
}
}
return when (this) {
HomeActionTone.Invite -> HomeActionColors( HomeActionTone.Invite -> HomeActionColors(
soft = CloserPalette.PurpleSoft, soft = CloserPalette.PurpleSoft,
accent = MaterialTheme.colorScheme.primary, accent = MaterialTheme.colorScheme.primary,
deep = CloserPalette.PurpleDeep deep = CloserPalette.PurpleDeep,
onAccent = MaterialTheme.colorScheme.onPrimary
) )
HomeActionTone.Daily -> HomeActionColors( HomeActionTone.Daily -> HomeActionColors(
soft = CloserPalette.PinkSoft, soft = CloserPalette.PinkSoft,
accent = CloserPalette.PinkBright, accent = CloserPalette.PinkBright,
deep = CloserPalette.PinkAccentDeep deep = CloserPalette.PinkAccentDeep,
onAccent = Color(0xFF24122F)
) )
HomeActionTone.Reflection -> HomeActionColors( HomeActionTone.Reflection -> HomeActionColors(
soft = CloserPalette.PurpleGlow, soft = CloserPalette.PurpleGlow,
accent = CloserPalette.PurpleRich, accent = CloserPalette.PurpleRich,
deep = CloserPalette.PurpleDeep deep = CloserPalette.PurpleDeep,
onAccent = Color(0xFF24122F)
) )
HomeActionTone.Ritual -> HomeActionColors( HomeActionTone.Ritual -> HomeActionColors(
soft = CloserPalette.PurpleSoft, soft = CloserPalette.PurpleSoft,
accent = CloserPalette.PinkBright, accent = CloserPalette.PinkBright,
deep = CloserPalette.PinkAccentDeep deep = CloserPalette.PinkAccentDeep,
onAccent = Color(0xFF24122F)
) )
HomeActionTone.Starter -> HomeActionColors( HomeActionTone.Starter -> HomeActionColors(
soft = CloserPalette.PinkSoft, soft = CloserPalette.PinkSoft,
accent = CloserPalette.PinkBright, accent = CloserPalette.PinkBright,
deep = CloserPalette.PinkAccentDeep deep = CloserPalette.PinkAccentDeep,
onAccent = Color(0xFF24122F)
) )
HomeActionTone.Pack -> HomeActionColors( HomeActionTone.Pack -> HomeActionColors(
soft = CloserPalette.PinkSoft, soft = CloserPalette.PinkSoft,
accent = CloserPalette.PinkBright, accent = CloserPalette.PinkBright,
deep = CloserPalette.PinkAccentDeep deep = CloserPalette.PinkAccentDeep,
onAccent = Color(0xFF24122F)
) )
HomeActionTone.Utility -> HomeActionColors( HomeActionTone.Utility -> HomeActionColors(
soft = CloserPalette.PurpleSoft, soft = CloserPalette.PurpleSoft,
accent = MaterialTheme.colorScheme.primary, accent = MaterialTheme.colorScheme.primary,
deep = CloserPalette.PurpleDeep deep = CloserPalette.PurpleDeep,
onAccent = MaterialTheme.colorScheme.onPrimary
) )
HomeActionTone.Pending -> HomeActionColors( HomeActionTone.Pending -> HomeActionColors(
soft = CloserPalette.PurpleSoft, soft = CloserPalette.PurpleSoft,
accent = MaterialTheme.colorScheme.primary, accent = MaterialTheme.colorScheme.primary,
deep = CloserPalette.PurpleDeep deep = CloserPalette.PurpleDeep,
onAccent = MaterialTheme.colorScheme.onPrimary
) )
} }
}
@Composable @Composable
private fun CategoryPreviewGrid( private fun CategoryPreviewGrid(
@ -1239,7 +1305,11 @@ private fun EmptyHomeContent(
private fun HomePill(label: String) { private fun HomePill(label: String) {
CloserPill( CloserPill(
label = label, label = label,
containerColor = CloserPalette.PinkMist.copy(alpha = 0.72f), containerColor = if (isCloserDarkTheme()) {
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.78f)
} else {
CloserPalette.PinkMist.copy(alpha = 0.72f)
},
contentColor = MaterialTheme.colorScheme.onSurface contentColor = MaterialTheme.colorScheme.onSurface
) )
} }

View File

@ -49,7 +49,6 @@ import app.closer.ui.components.CloserClickableCard
import app.closer.ui.components.CloserElevations import app.closer.ui.components.CloserElevations
import app.closer.ui.components.CloserPill import app.closer.ui.components.CloserPill
import app.closer.ui.components.CloserRadii import app.closer.ui.components.CloserRadii
import app.closer.ui.theme.CloserPalette
import app.closer.ui.theme.closerBackgroundBrush import app.closer.ui.theme.closerBackgroundBrush
import app.closer.ui.theme.closerPlayCardBrush import app.closer.ui.theme.closerPlayCardBrush
@ -147,7 +146,7 @@ private fun PlayHubContent(
title = "Date Match", title = "Date Match",
subtitle = "Swipe ideas", subtitle = "Swipe ideas",
icon = Icons.Filled.Favorite, icon = Icons.Filled.Favorite,
tint = CloserPalette.Romantic, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
onClick = { onNavigate(AppRoute.DATE_MATCH) } onClick = { onNavigate(AppRoute.DATE_MATCH) }
) )
@ -155,7 +154,7 @@ private fun PlayHubContent(
title = "Plan Date", title = "Plan Date",
subtitle = "Set the shape", subtitle = "Set the shape",
icon = Icons.Filled.Star, icon = Icons.Filled.Star,
tint = CloserPalette.Gold, tint = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
onClick = { onNavigate(AppRoute.DATE_BUILDER) } onClick = { onNavigate(AppRoute.DATE_BUILDER) }
) )
@ -171,7 +170,7 @@ private fun PlayHubContent(
title = "Bucket List", title = "Bucket List",
subtitle = "Save ideas", subtitle = "Save ideas",
icon = Icons.Filled.Done, icon = Icons.Filled.Done,
tint = CloserPalette.Evergreen, tint = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
onClick = { onNavigate(AppRoute.BUCKET_LIST) } onClick = { onNavigate(AppRoute.BUCKET_LIST) }
) )
@ -179,7 +178,7 @@ private fun PlayHubContent(
title = "Past Games", title = "Past Games",
subtitle = "All results", subtitle = "All results",
icon = Icons.Filled.Home, icon = Icons.Filled.Home,
tint = CloserPalette.PurpleDeep, tint = MaterialTheme.colorScheme.primary,
locked = !hasPremium, locked = !hasPremium,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
onClick = { onNavigate(AppRoute.GAME_HISTORY) } onClick = { onNavigate(AppRoute.GAME_HISTORY) }
@ -212,14 +211,14 @@ private fun ThisOrThatCard(
) { ) {
Surface( Surface(
shape = RoundedCornerShape(CloserRadii.Tile), shape = RoundedCornerShape(CloserRadii.Tile),
color = CloserPalette.PinkMist, color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.78f),
modifier = Modifier.size(52.dp) modifier = Modifier.size(52.dp)
) { ) {
Box(contentAlignment = Alignment.Center) { Box(contentAlignment = Alignment.Center) {
Text( Text(
text = "A/B", text = "A/B",
style = MaterialTheme.typography.titleSmall.copy(fontWeight = FontWeight.Bold), style = MaterialTheme.typography.titleSmall.copy(fontWeight = FontWeight.Bold),
color = CloserPalette.PinkAccentDeep color = MaterialTheme.colorScheme.onSecondaryContainer
) )
} }
} }
@ -241,8 +240,8 @@ private fun ThisOrThatCard(
) )
CloserPill( CloserPill(
label = "10 prompts", label = "10 prompts",
containerColor = CloserPalette.PinkMist, containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.78f),
contentColor = CloserPalette.PinkAccentDeep contentColor = MaterialTheme.colorScheme.onSecondaryContainer
) )
} }
Text( Text(
@ -256,7 +255,7 @@ private fun ThisOrThatCard(
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward, imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = null, contentDescription = null,
tint = CloserPalette.PinkAccentDeep, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }
@ -305,7 +304,7 @@ private fun DesireSyncCard(
) )
Surface( Surface(
shape = RoundedCornerShape(CloserRadii.Pill), shape = RoundedCornerShape(CloserRadii.Pill),
color = CloserPalette.Romantic.copy(alpha = 0.12f) color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.66f)
) { ) {
Row( Row(
modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp), modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp),
@ -315,13 +314,13 @@ private fun DesireSyncCard(
Icon( Icon(
imageVector = Icons.Filled.Lock, imageVector = Icons.Filled.Lock,
contentDescription = null, contentDescription = null,
tint = CloserPalette.Romantic, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(13.dp) modifier = Modifier.size(13.dp)
) )
Text( Text(
text = "Premium", text = "Premium",
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = CloserPalette.Romantic, color = MaterialTheme.colorScheme.onSecondaryContainer,
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold
) )
} }
@ -338,7 +337,7 @@ private fun DesireSyncCard(
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward, imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = null, contentDescription = null,
tint = CloserPalette.Romantic, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }
@ -388,8 +387,8 @@ private fun HowWellCard(
) )
CloserPill( CloserPill(
label = "10 rounds", label = "10 rounds",
containerColor = CloserPalette.Romantic.copy(alpha = 0.12f), containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.66f),
contentColor = CloserPalette.Romantic contentColor = MaterialTheme.colorScheme.onSecondaryContainer
) )
} }
Text( Text(
@ -403,7 +402,7 @@ private fun HowWellCard(
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward, imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = null, contentDescription = null,
tint = CloserPalette.Romantic, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }
@ -432,7 +431,7 @@ private fun ConnectionChallengesCard(
) { ) {
Surface( Surface(
shape = RoundedCornerShape(CloserRadii.Tile), shape = RoundedCornerShape(CloserRadii.Tile),
color = CloserPalette.PurpleDeep.copy(alpha = 0.12f), color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.66f),
modifier = Modifier.size(52.dp) modifier = Modifier.size(52.dp)
) { ) {
Box(contentAlignment = Alignment.Center) { Box(contentAlignment = Alignment.Center) {
@ -460,8 +459,8 @@ private fun ConnectionChallengesCard(
) )
CloserPill( CloserPill(
label = "7 days", label = "7 days",
containerColor = CloserPalette.PurpleDeep.copy(alpha = 0.10f), containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.66f),
contentColor = CloserPalette.PurpleDeep contentColor = MaterialTheme.colorScheme.onPrimaryContainer
) )
} }
Text( Text(
@ -475,7 +474,7 @@ private fun ConnectionChallengesCard(
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward, imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = null, contentDescription = null,
tint = CloserPalette.PurpleDeep, tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }
@ -504,7 +503,7 @@ private fun MemoryLaneCard(
) { ) {
Surface( Surface(
shape = RoundedCornerShape(CloserRadii.Tile), shape = RoundedCornerShape(CloserRadii.Tile),
color = CloserPalette.Romantic.copy(alpha = 0.12f), color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.66f),
modifier = Modifier.size(52.dp) modifier = Modifier.size(52.dp)
) { ) {
Box(contentAlignment = Alignment.Center) { Box(contentAlignment = Alignment.Center) {
@ -530,7 +529,7 @@ private fun MemoryLaneCard(
) )
Surface( Surface(
shape = RoundedCornerShape(CloserRadii.Pill), shape = RoundedCornerShape(CloserRadii.Pill),
color = CloserPalette.Romantic.copy(alpha = 0.12f) color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.66f)
) { ) {
Row( Row(
modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp), modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp),
@ -540,13 +539,13 @@ private fun MemoryLaneCard(
Icon( Icon(
imageVector = Icons.Filled.Lock, imageVector = Icons.Filled.Lock,
contentDescription = null, contentDescription = null,
tint = CloserPalette.Romantic, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(13.dp) modifier = Modifier.size(13.dp)
) )
Text( Text(
text = "Premium", text = "Premium",
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = CloserPalette.Romantic, color = MaterialTheme.colorScheme.onSecondaryContainer,
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold
) )
} }
@ -563,7 +562,7 @@ private fun MemoryLaneCard(
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward, imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = null, contentDescription = null,
tint = CloserPalette.Romantic, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }
@ -595,12 +594,12 @@ private fun FeaturedPlayCard(
CloserPill( CloserPill(
label = "Wheel", label = "Wheel",
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.72f), containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.72f),
contentColor = CloserPalette.PurpleDeep contentColor = MaterialTheme.colorScheme.onSurface
) )
CloserPill( CloserPill(
label = "10 prompts", label = "10 prompts",
containerColor = MaterialTheme.colorScheme.secondaryContainer, containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = CloserPalette.PinkAccentDeep contentColor = MaterialTheme.colorScheme.onSecondaryContainer
) )
} }
@ -640,8 +639,8 @@ private fun FeaturedPlayCard(
.fillMaxWidth() .fillMaxWidth()
.heightIn(min = 54.dp), .heightIn(min = 54.dp),
style = CloserButtonStyle.Primary, style = CloserButtonStyle.Primary,
containerColor = CloserPalette.PurpleDeep, containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.surface contentColor = MaterialTheme.colorScheme.onPrimary
) )
} }
} }
@ -706,14 +705,14 @@ private fun CompactPlayCard(
Icon( Icon(
imageVector = Icons.Filled.Lock, imageVector = Icons.Filled.Lock,
contentDescription = null, contentDescription = null,
tint = CloserPalette.Gold, tint = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.size(11.dp) modifier = Modifier.size(11.dp)
) )
} }
Text( Text(
text = if (locked) "Premium" else subtitle, text = if (locked) "Premium" else subtitle,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = if (locked) CloserPalette.Gold else MaterialTheme.colorScheme.onSurfaceVariant, color = if (locked) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )

View File

@ -1,6 +1,7 @@
package app.closer.ui.questions package app.closer.ui.questions
import app.closer.ui.theme.closerBackgroundBrush import app.closer.ui.theme.closerBackgroundBrush
import app.closer.ui.theme.closerCardColor
import android.provider.Settings import android.provider.Settings
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
@ -153,8 +154,8 @@ fun LocalQuestionContent(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4), containerColor = MaterialTheme.colorScheme.primary,
contentColor = Color(0xFF24122F) contentColor = MaterialTheme.colorScheme.onPrimary
) )
) { ) {
Text( Text(
@ -203,7 +204,7 @@ private fun LocalQuestionHeader(
Surface( Surface(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(28.dp), shape = RoundedCornerShape(28.dp),
color = Color.White.copy(alpha = 0.82f), color = closerCardColor(alpha = 0.92f),
shadowElevation = 5.dp shadowElevation = 5.dp
) { ) {
Column( Column(
@ -258,7 +259,7 @@ private fun SubmittedAnswerCard(
Surface( Surface(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(22.dp), shape = RoundedCornerShape(22.dp),
color = Color.White.copy(alpha = 0.78f), color = closerCardColor(alpha = 0.86f),
shadowElevation = 0.dp shadowElevation = 0.dp
) { ) {
Row( Row(
@ -270,13 +271,13 @@ private fun SubmittedAnswerCard(
modifier = Modifier modifier = Modifier
.size(36.dp) .size(36.dp)
.clip(CircleShape) .clip(CircleShape)
.background(Color(0xFFB98AF4).copy(alpha = 0.18f)), .background(MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.58f)),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Text( Text(
text = badge, text = badge,
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = Color(0xFF56306F), color = MaterialTheme.colorScheme.onPrimaryContainer,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
} }

View File

@ -151,10 +151,10 @@ private fun QuestionCategoryContent(
.heightIn(min = 54.dp), .heightIn(min = 54.dp),
shape = RoundedCornerShape(18.dp), shape = RoundedCornerShape(18.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF56306F), containerColor = MaterialTheme.colorScheme.primary,
contentColor = Color.White, contentColor = MaterialTheme.colorScheme.onPrimary,
disabledContainerColor = Color(0xFF56306F).copy(alpha = 0.35f), disabledContainerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.35f),
disabledContentColor = Color.White.copy(alpha = 0.54f) disabledContentColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.54f)
) )
) { ) {
Text( Text(

View File

@ -1,11 +1,11 @@
package app.closer.ui.questions package app.closer.ui.questions
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.material3.MaterialTheme
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import app.closer.core.navigation.AppRoute import app.closer.core.navigation.AppRoute
import app.closer.ui.components.FinishedEmptyStateAction import app.closer.ui.components.FinishedEmptyStateAction
import app.closer.ui.components.FinishedEmptyStateScreen import app.closer.ui.components.FinishedEmptyStateScreen
import app.closer.ui.theme.CloserPalette
@Composable @Composable
fun QuestionComposerScreen( fun QuestionComposerScreen(
@ -18,7 +18,7 @@ fun QuestionComposerScreen(
glyphCategoryId = "question", glyphCategoryId = "question",
primaryAction = FinishedEmptyStateAction("Browse packs", AppRoute.QUESTION_PACKS), primaryAction = FinishedEmptyStateAction("Browse packs", AppRoute.QUESTION_PACKS),
secondaryAction = FinishedEmptyStateAction("Daily question", AppRoute.DAILY_QUESTION), secondaryAction = FinishedEmptyStateAction("Daily question", AppRoute.DAILY_QUESTION),
accent = CloserPalette.PurpleDeep, accent = MaterialTheme.colorScheme.primary,
details = listOf( details = listOf(
"Choose prompts already shaped for real conversation.", "Choose prompts already shaped for real conversation.",
"Keep the next step focused on answering, not drafting.", "Keep the next step focused on answering, not drafting.",

View File

@ -184,7 +184,7 @@ private fun QuestionPackLibraryContent(
.padding(top = 6.dp, bottom = 22.dp), .padding(top = 6.dp, bottom = 22.dp),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4), containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary contentColor = MaterialTheme.colorScheme.onPrimary
) )
) { ) {
@ -373,13 +373,14 @@ private fun QuestionPackItem.metadataLabels(): List<String> {
).filterNot { it == "Question" }.distinct() ).filterNot { it == "Question" }.distinct()
} }
@Composable
private fun packAccent(categoryId: String): Color { private fun packAccent(categoryId: String): Color {
val palette = listOf( val palette = listOf(
Color(0xFF56306F), MaterialTheme.colorScheme.primary,
Color(0xFF8A4BC1), MaterialTheme.colorScheme.secondary,
Color(0xFFB98AF4), MaterialTheme.colorScheme.tertiary,
Color(0xFFB65F93), MaterialTheme.colorScheme.primaryContainer,
Color(0xFFE7A2D1) MaterialTheme.colorScheme.secondaryContainer
) )
return palette[kotlin.math.abs(categoryId.hashCode()) % palette.size] return palette[kotlin.math.abs(categoryId.hashCode()) % palette.size]
} }

View File

@ -263,8 +263,8 @@ private fun RevealedPhase(
modifier = Modifier.weight(1f).heightIn(min = 48.dp), modifier = Modifier.weight(1f).heightIn(min = 48.dp),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4), containerColor = MaterialTheme.colorScheme.primary,
contentColor = Color(0xFF24122F) contentColor = MaterialTheme.colorScheme.onPrimary
) )
) { ) {
Text("Next prompt") Text("Next prompt")

View File

@ -47,7 +47,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.closer.R import app.closer.R
import app.closer.core.navigation.ExternalLinks import app.closer.core.navigation.ExternalLinks
import app.closer.ui.theme.CloserPalette
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -94,7 +93,7 @@ fun PrivacyScreen(
// ── What your partner can see ───────────────────────────────────── // ── What your partner can see ─────────────────────────────────────
PrivacySectionHeader( PrivacySectionHeader(
icon = Icons.Default.CheckCircle, icon = Icons.Default.CheckCircle,
iconTint = CloserPalette.PurpleDeep, iconTint = SettingsPrimary,
title = stringResource(R.string.privacy_section_partner_visible) title = stringResource(R.string.privacy_section_partner_visible)
) )
@ -139,7 +138,7 @@ fun PrivacyScreen(
// ── What stays private ──────────────────────────────────────────── // ── What stays private ────────────────────────────────────────────
PrivacySectionHeader( PrivacySectionHeader(
icon = Icons.Default.Lock, icon = Icons.Default.Lock,
iconTint = CloserPalette.Romantic, iconTint = MaterialTheme.colorScheme.secondary,
title = stringResource(R.string.privacy_section_data) title = stringResource(R.string.privacy_section_data)
) )

View File

@ -69,6 +69,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import app.closer.core.navigation.AppRoute import app.closer.core.navigation.AppRoute
import app.closer.domain.model.OutcomeDay import app.closer.domain.model.OutcomeDay
import app.closer.ui.components.OutcomeCheckInDialog import app.closer.ui.components.OutcomeCheckInDialog
import app.closer.ui.theme.isCloserDarkTheme
import app.closer.ui.settings.SettingsDanger import app.closer.ui.settings.SettingsDanger
import app.closer.ui.settings.SettingsInk import app.closer.ui.settings.SettingsInk
import app.closer.ui.settings.SettingsMuted import app.closer.ui.settings.SettingsMuted
@ -120,11 +121,16 @@ fun SettingsSection(
accent: Color = Color(0xFFF7C8E4), accent: Color = Color(0xFFF7C8E4),
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
val sectionAccent = if (isCloserDarkTheme()) {
MaterialTheme.colorScheme.primaryContainer
} else {
accent
}
Card( Card(
modifier = modifier modifier = modifier
.fillMaxWidth(), .fillMaxWidth(),
shape = RoundedCornerShape(22.dp), shape = RoundedCornerShape(22.dp),
colors = CardDefaults.cardColors(containerColor = accent.copy(alpha = 0.16f)), colors = CardDefaults.cardColors(containerColor = sectionAccent.copy(alpha = 0.16f)),
elevation = CardDefaults.cardElevation(defaultElevation = 5.dp) elevation = CardDefaults.cardElevation(defaultElevation = 5.dp)
) { ) {
Column( Column(

View File

@ -21,6 +21,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -129,7 +130,9 @@ class SettingsViewModel @Inject constructor(
private fun observeCurrentUser(userId: String) { private fun observeCurrentUser(userId: String) {
currentUserJob?.cancel() currentUserJob?.cancel()
currentUserJob = viewModelScope.launch { currentUserJob = viewModelScope.launch {
userRepository.observeUser(userId).collect { user -> userRepository.observeUser(userId)
.catch { error -> Log.w(TAG, "Current user observer stopped", error) }
.collect { user ->
_uiState.update { _uiState.update {
it.copy( it.copy(
displayName = user?.displayName ?: it.displayName, displayName = user?.displayName ?: it.displayName,
@ -147,7 +150,9 @@ class SettingsViewModel @Inject constructor(
return return
} }
partnerUserJob = viewModelScope.launch { partnerUserJob = viewModelScope.launch {
userRepository.observeUser(partnerId).collect { partner -> userRepository.observeUser(partnerId)
.catch { error -> Log.w(TAG, "Partner user observer stopped", error) }
.collect { partner ->
_uiState.update { _uiState.update {
it.copy( it.copy(
partnerName = partner?.displayName, partnerName = partner?.displayName,

View File

@ -6,17 +6,30 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import app.closer.ui.theme.isCloserDarkTheme
internal val SettingsBackgroundBrush: Brush internal val SettingsBackgroundBrush: Brush
@Composable @Composable
get() = Brush.linearGradient( get() {
colors = listOf( val colors = if (isCloserDarkTheme()) {
listOf(
MaterialTheme.colorScheme.background,
MaterialTheme.colorScheme.surface,
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.72f)
)
} else {
listOf(
MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.background,
MaterialTheme.colorScheme.surfaceVariant, MaterialTheme.colorScheme.surfaceVariant,
MaterialTheme.colorScheme.secondaryContainer MaterialTheme.colorScheme.secondaryContainer
), )
}
return Brush.linearGradient(
colors = colors,
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
}
internal val SettingsInk: Color internal val SettingsInk: Color
@Composable get() = MaterialTheme.colorScheme.onBackground @Composable get() = MaterialTheme.colorScheme.onBackground

View File

@ -55,7 +55,6 @@ import app.closer.core.navigation.ExternalLinks
import app.closer.domain.repository.BillingRepository import app.closer.domain.repository.BillingRepository
import app.closer.domain.repository.BillingState import app.closer.domain.repository.BillingState
import app.closer.ui.components.LoadingState import app.closer.ui.components.LoadingState
import app.closer.ui.theme.CloserPalette
import app.closer.ui.theme.closerBackgroundBrush import app.closer.ui.theme.closerBackgroundBrush
import app.closer.ui.theme.closerCardColor import app.closer.ui.theme.closerCardColor
import com.revenuecat.purchases.CustomerInfo import com.revenuecat.purchases.CustomerInfo
@ -205,7 +204,7 @@ private fun PremiumContent(
Surface( Surface(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(24.dp), shape = RoundedCornerShape(24.dp),
color = CloserPalette.PurpleDeep.copy(alpha = 0.08f), color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.24f),
shadowElevation = 0.dp shadowElevation = 0.dp
) { ) {
Column( Column(
@ -252,7 +251,7 @@ private fun PremiumContent(
Icon( Icon(
imageVector = Icons.Filled.Check, imageVector = Icons.Filled.Check,
contentDescription = null, contentDescription = null,
tint = CloserPalette.PurpleDeep, tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp) modifier = Modifier.size(16.dp)
) )
Text( Text(
@ -270,8 +269,8 @@ private fun PremiumContent(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = CloserPalette.PurpleDeep, containerColor = MaterialTheme.colorScheme.primary,
contentColor = Color.White contentColor = MaterialTheme.colorScheme.onPrimary
) )
) { ) {
Icon( Icon(
@ -353,7 +352,7 @@ private fun FreeContent(
Icon( Icon(
imageVector = Icons.Filled.Check, imageVector = Icons.Filled.Check,
contentDescription = null, contentDescription = null,
tint = CloserPalette.PurpleDeep, tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp) modifier = Modifier.size(16.dp)
) )
Text( Text(
@ -371,8 +370,8 @@ private fun FreeContent(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = CloserPalette.PurpleDeep, containerColor = MaterialTheme.colorScheme.primary,
contentColor = Color.White contentColor = MaterialTheme.colorScheme.onPrimary
) )
) { ) {
Text("Upgrade to Premium", fontWeight = FontWeight.SemiBold) Text("Upgrade to Premium", fontWeight = FontWeight.SemiBold)

View File

@ -1,11 +1,11 @@
package app.closer.ui.theme package app.closer.ui.theme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
object CloserPalette { object CloserPalette {
val BackgroundWash = Color(0xFFF8F1FF) val BackgroundWash = Color(0xFFF8F1FF)
@ -28,6 +28,17 @@ object CloserPalette {
@Composable @Composable
fun closerBackgroundBrush(): Brush = fun closerBackgroundBrush(): Brush =
if (isCloserDarkTheme()) {
Brush.linearGradient(
colors = listOf(
MaterialTheme.colorScheme.background,
MaterialTheme.colorScheme.surface,
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.72f)
),
start = Offset.Zero,
end = Offset.Infinite
)
} else {
Brush.linearGradient( Brush.linearGradient(
colors = listOf( colors = listOf(
MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.background,
@ -37,6 +48,7 @@ fun closerBackgroundBrush(): Brush =
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
}
@Composable @Composable
fun closerInkColor(): Color = MaterialTheme.colorScheme.onSurface fun closerInkColor(): Color = MaterialTheme.colorScheme.onSurface
@ -62,7 +74,7 @@ fun closerSolidCardColor(): Color = MaterialTheme.colorScheme.surface
@Composable @Composable
fun closerSoftSurfaceColor(alpha: Float = 0.92f): Color = fun closerSoftSurfaceColor(alpha: Float = 0.92f): Color =
if (isSystemInDarkTheme()) { if (isCloserDarkTheme()) {
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = alpha) MaterialTheme.colorScheme.surfaceVariant.copy(alpha = alpha)
} else { } else {
Color.White.copy(alpha = alpha) Color.White.copy(alpha = alpha)
@ -70,7 +82,7 @@ fun closerSoftSurfaceColor(alpha: Float = 0.92f): Color =
@Composable @Composable
fun closerSoftPurpleColor(alpha: Float = 1f): Color = fun closerSoftPurpleColor(alpha: Float = 1f): Color =
if (isSystemInDarkTheme()) { if (isCloserDarkTheme()) {
MaterialTheme.colorScheme.primaryContainer.copy(alpha = alpha) MaterialTheme.colorScheme.primaryContainer.copy(alpha = alpha)
} else { } else {
CloserPalette.PurpleMist.copy(alpha = alpha) CloserPalette.PurpleMist.copy(alpha = alpha)
@ -78,7 +90,7 @@ fun closerSoftPurpleColor(alpha: Float = 1f): Color =
@Composable @Composable
fun closerSoftPinkColor(alpha: Float = 1f): Color = fun closerSoftPinkColor(alpha: Float = 1f): Color =
if (isSystemInDarkTheme()) { if (isCloserDarkTheme()) {
MaterialTheme.colorScheme.secondaryContainer.copy(alpha = alpha) MaterialTheme.colorScheme.secondaryContainer.copy(alpha = alpha)
} else { } else {
CloserPalette.PinkMist.copy(alpha = alpha) CloserPalette.PinkMist.copy(alpha = alpha)
@ -91,11 +103,19 @@ fun closerScrimColor(alpha: Float = 0.54f): Color =
@Composable @Composable
fun closerPlayCardBrush(): Brush = fun closerPlayCardBrush(): Brush =
Brush.linearGradient( Brush.linearGradient(
colors = listOf( colors = if (isCloserDarkTheme()) {
listOf(
MaterialTheme.colorScheme.surface,
MaterialTheme.colorScheme.surfaceVariant,
MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.78f)
)
} else {
listOf(
MaterialTheme.colorScheme.surface, MaterialTheme.colorScheme.surface,
MaterialTheme.colorScheme.primaryContainer, MaterialTheme.colorScheme.primaryContainer,
MaterialTheme.colorScheme.secondaryContainer MaterialTheme.colorScheme.secondaryContainer
), )
},
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@ -106,14 +126,27 @@ fun closerBrandGlyphBrush(): Brush =
colors = listOf( colors = listOf(
MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.primary,
MaterialTheme.colorScheme.secondary, MaterialTheme.colorScheme.secondary,
CloserPalette.PurpleDeep if (isCloserDarkTheme()) MaterialTheme.colorScheme.tertiary else CloserPalette.PurpleDeep
), ),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@Composable @Composable
fun closerWheelSegmentColors(): List<Color> = listOf( fun closerWheelSegmentColors(): List<Color> =
if (isCloserDarkTheme()) {
listOf(
MaterialTheme.colorScheme.primary,
MaterialTheme.colorScheme.secondary,
MaterialTheme.colorScheme.tertiary,
MaterialTheme.colorScheme.primaryContainer,
MaterialTheme.colorScheme.secondaryContainer,
MaterialTheme.colorScheme.tertiaryContainer,
MaterialTheme.colorScheme.surfaceVariant,
MaterialTheme.colorScheme.outline
)
} else {
listOf(
MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.primary,
CloserPalette.PinkWheel, CloserPalette.PinkWheel,
MaterialTheme.colorScheme.secondary, MaterialTheme.colorScheme.secondary,
@ -123,3 +156,7 @@ fun closerWheelSegmentColors(): List<Color> = listOf(
CloserPalette.PurpleDeep, CloserPalette.PurpleDeep,
CloserPalette.PinkShell CloserPalette.PinkShell
) )
}
@Composable
fun isCloserDarkTheme(): Boolean = MaterialTheme.colorScheme.background.luminance() < 0.5f

View File

@ -3,18 +3,18 @@ package app.closer.ui.theme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
// Dark theme colors (for reference if needed) // Dark theme colors (for reference if needed)
val darkPrimaryColor = Color(0xFFB98AF4) val darkPrimaryColor = Color(0xFFD7BBFF)
val darkPrimaryContainerColor = Color(0xFF43255F) val darkPrimaryContainerColor = Color(0xFF4D3865)
val darkSecondaryColor = Color(0xFFFFAFD9) val darkSecondaryColor = Color(0xFFE8B7D0)
val darkTertiaryColor = Color(0xFFB98AF4) val darkTertiaryColor = Color(0xFFC9C1FF)
val darkBackgroundColor = Color(0xFF18111E) val darkBackgroundColor = Color(0xFF111015)
val darkSurfaceColor = Color(0xFF211729) val darkSurfaceColor = Color(0xFF19161F)
val darkErrorColor = Color(0xFFFFB3BA) val darkErrorColor = Color(0xFFFFB4AB)
val darkOnPrimaryColor = Color(0xFFFFFFFF) val darkOnPrimaryColor = Color(0xFF37204E)
val darkOnPrimaryContainerColor = Color(0xFFF3E8FF) val darkOnPrimaryContainerColor = Color(0xFFF2E8FF)
val darkOnSecondaryColor = Color(0xFFFFFFFF) val darkOnSecondaryColor = Color(0xFF482638)
val darkOnTertiaryColor = Color(0xFF24122F) val darkOnTertiaryColor = Color(0xFF302A55)
val darkOnBackgroundColor = Color(0xFFF2E8F6) val darkOnBackgroundColor = Color(0xFFEDE7EF)
val darkOnSurfaceColor = Color(0xFFF2E8F6) val darkOnSurfaceColor = Color(0xFFEDE7EF)
val darkOnErrorColor = Color(0xFFFFFFFF) val darkOnErrorColor = Color(0xFF690005)

View File

@ -22,25 +22,25 @@ fun CloserTheme(
) )
} }
// Purple-pink color palette (Light theme) // Brand palette. Keep accent color in containers and controls; large surfaces stay quiet.
val PrimaryColor = Color(0xFFB98AF4) val PrimaryColor = Color(0xFF7B4DB2)
val PrimaryContainerColor = Color(0xFFF3E8FF) val PrimaryContainerColor = Color(0xFFF1E7FF)
val SecondaryColor = Color(0xFFE7A2D1) val SecondaryColor = Color(0xFF9B4F78)
val TertiaryColor = Color(0xFFB98AF4) val TertiaryColor = Color(0xFF6B5AA6)
val BackgroundColor = Color(0xFFFFFBFE) val BackgroundColor = Color(0xFFFFFBFF)
val SurfaceColor = Color(0xFFFFFBFE) val SurfaceColor = Color(0xFFFFFBFF)
val ErrorColor = Color(0xFF8D2D35) val ErrorColor = Color(0xFFBA1A1A)
val SurfaceVariantColor = Color(0xFFF4E8FF) val SurfaceVariantColor = Color(0xFFF0E8F4)
val OutlineColor = Color(0xFF9B8AA6) val OutlineColor = Color(0xFF807581)
val OutlineVariantColor = Color(0xFFE3D4EB) val OutlineVariantColor = Color(0xFFD2C7D5)
val OnPrimaryColor = Color(0xFF24122F) val OnPrimaryColor = Color(0xFFFFFFFF)
val OnPrimaryContainerColor = Color(0xFF321545) val OnPrimaryContainerColor = Color(0xFF29123F)
val OnSecondaryColor = Color(0xFF2E1731) val OnSecondaryColor = Color(0xFFFFFFFF)
val OnTertiaryColor = Color(0xFF24122F) val OnTertiaryColor = Color(0xFFFFFFFF)
val OnBackgroundColor = Color(0xFF261D2E) val OnBackgroundColor = Color(0xFF211A24)
val OnSurfaceColor = Color(0xFF261D2E) val OnSurfaceColor = Color(0xFF211A24)
val OnSurfaceVariantColor = Color(0xFF5A5060) val OnSurfaceVariantColor = Color(0xFF514957)
val OnErrorColor = Color(0xFFFFFFFF) val OnErrorColor = Color(0xFFFFFFFF)
val lightColors = lightColorScheme( val lightColors = lightColorScheme(
@ -50,11 +50,11 @@ val lightColors = lightColorScheme(
onPrimaryContainer = OnPrimaryContainerColor, onPrimaryContainer = OnPrimaryContainerColor,
secondary = SecondaryColor, secondary = SecondaryColor,
onSecondary = OnSecondaryColor, onSecondary = OnSecondaryColor,
secondaryContainer = Color(0xFFFFE8F4), secondaryContainer = Color(0xFFFFD8E9),
onSecondaryContainer = Color(0xFF3B1730), onSecondaryContainer = Color(0xFF3B1730),
tertiary = TertiaryColor, tertiary = TertiaryColor,
onTertiary = OnTertiaryColor, onTertiary = OnTertiaryColor,
tertiaryContainer = Color(0xFFF4E8FF), tertiaryContainer = Color(0xFFE9E3FF),
onTertiaryContainer = Color(0xFF321545), onTertiaryContainer = Color(0xFF321545),
background = BackgroundColor, background = BackgroundColor,
surface = SurfaceColor, surface = SurfaceColor,
@ -69,26 +69,33 @@ val lightColors = lightColorScheme(
) )
val darkColors = darkColorScheme( val darkColors = darkColorScheme(
primary = Color(0xFFCFA7FF), primary = Color(0xFFD7BBFF),
onPrimary = Color(0xFF2A1238), onPrimary = Color(0xFF37204E),
primaryContainer = Color(0xFF43255F), primaryContainer = Color(0xFF4D3865),
onPrimaryContainer = Color(0xFFF3E8FF), onPrimaryContainer = Color(0xFFF2E8FF),
secondary = Color(0xFFFFAFD9), secondary = Color(0xFFE8B7D0),
onSecondary = Color(0xFF3B1730), onSecondary = Color(0xFF482638),
secondaryContainer = Color(0xFF5B2847), secondaryContainer = Color(0xFF3D2C36),
onSecondaryContainer = Color(0xFFFFD8EB), onSecondaryContainer = Color(0xFFFFD8EA),
tertiary = Color(0xFFB98AF4), tertiary = Color(0xFFC9C1FF),
onTertiary = Color(0xFF24122F), onTertiary = Color(0xFF302A55),
tertiaryContainer = Color(0xFF43255F), tertiaryContainer = Color(0xFF343047),
onTertiaryContainer = Color(0xFFF3E8FF), onTertiaryContainer = Color(0xFFE8E2FF),
background = Color(0xFF18111E), background = Color(0xFF111015),
surface = Color(0xFF211729), surface = Color(0xFF19161F),
onBackground = Color(0xFFF2E8F6), onBackground = Color(0xFFEDE7EF),
onSurface = Color(0xFFF2E8F6), onSurface = Color(0xFFEDE7EF),
surfaceVariant = Color(0xFF372641), surfaceVariant = Color(0xFF2D2933),
onSurfaceVariant = Color(0xFFD9C8E2), onSurfaceVariant = Color(0xFFD3C8D8),
outline = Color(0xFFA996B4), outline = Color(0xFF9E93A4),
outlineVariant = Color(0xFF5A4666), outlineVariant = Color(0xFF4D4653),
error = Color(0xFFFFB3BA), error = Color(0xFFFFB4AB),
onError = OnErrorColor onError = Color(0xFF690005),
errorContainer = Color(0xFF93000A),
onErrorContainer = Color(0xFFFFDAD6),
inverseSurface = Color(0xFFEDE7EF),
inverseOnSurface = Color(0xFF322F36),
inversePrimary = Color(0xFF6D45A0),
surfaceTint = Color(0xFFD7BBFF),
scrim = Color(0xFF000000)
) )