refactor: extract shared auth/settings visuals, apply consistent theme across screens

This commit is contained in:
null 2026-06-16 04:16:16 -05:00
parent 0f73c656d8
commit 71441bec14
30 changed files with 427 additions and 174 deletions

View File

@ -0,0 +1,35 @@
package com.couplesconnect.app.ui.auth
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
internal val AuthBackgroundBrush: Brush
get() = Brush.linearGradient(
colors = listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero,
end = Offset.Infinite
)
internal val AuthInk = Color(0xFF261D2E)
internal val AuthMuted = Color(0xFF5A5060)
internal val AuthPrimary = Color(0xFFB98AF4)
internal val AuthPrimaryDeep = Color(0xFF56306F)
internal val AuthOnPrimary = Color(0xFF24122F)
@Composable
internal fun authTextFieldColors() = OutlinedTextFieldDefaults.colors(
focusedBorderColor = AuthPrimaryDeep,
unfocusedBorderColor = AuthMuted.copy(alpha = 0.24f),
focusedLabelColor = AuthPrimaryDeep,
unfocusedLabelColor = AuthMuted,
cursorColor = AuthPrimaryDeep,
focusedContainerColor = Color.White.copy(alpha = 0.92f),
unfocusedContainerColor = Color.White.copy(alpha = 0.78f),
focusedTextColor = AuthInk,
unfocusedTextColor = AuthInk,
focusedTrailingIconColor = AuthPrimaryDeep,
unfocusedTrailingIconColor = AuthMuted
)

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.auth package com.couplesconnect.app.ui.auth
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -30,6 +31,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -37,6 +39,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
@ -61,14 +64,21 @@ fun ForgotPasswordScreen(
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(snackbar) }, snackbarHost = { SnackbarHost(snackbar) },
containerColor = Color.Transparent,
modifier = Modifier.background(AuthBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate(AppRoute.LOGIN) }) { IconButton(onClick = { onNavigate(AppRoute.LOGIN) }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = AuthInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -87,32 +97,37 @@ fun ForgotPasswordScreen(
if (state.sent) { if (state.sent) {
Spacer(Modifier.height(48.dp)) Spacer(Modifier.height(48.dp))
Text("", style = MaterialTheme.typography.displayMedium, color = MaterialTheme.colorScheme.secondary) Text("", style = MaterialTheme.typography.displayMedium, color = AuthPrimaryDeep)
Spacer(Modifier.height(16.dp)) Spacer(Modifier.height(16.dp))
Text("Reset email sent", style = MaterialTheme.typography.headlineSmall, textAlign = TextAlign.Center) Text(
"Reset email sent",
style = MaterialTheme.typography.headlineSmall,
color = AuthInk,
textAlign = TextAlign.Center
)
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
Text( Text(
"Check your inbox and follow the link to reset your password.", "Check your inbox and follow the link to reset your password.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), color = AuthMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(32.dp)) Spacer(Modifier.height(32.dp))
TextButton(onClick = { onNavigate(AppRoute.LOGIN) }) { TextButton(onClick = { onNavigate(AppRoute.LOGIN) }) {
Text("Back to sign in", color = MaterialTheme.colorScheme.primary) Text("Back to sign in", color = AuthPrimaryDeep)
} }
} else { } else {
Text( Text(
"Reset your access", "Reset your access",
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary, color = AuthInk,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
Text( Text(
"Enter your email and we'll send a reset link.", "Enter your email and we'll send a reset link.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), color = AuthMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(32.dp)) Spacer(Modifier.height(32.dp))
@ -122,6 +137,7 @@ fun ForgotPasswordScreen(
label = { Text("Email") }, label = { Text("Email") },
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = authTextFieldColors(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email, imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus(); viewModel.sendReset() }) keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus(); viewModel.sendReset() })
) )
@ -130,11 +146,14 @@ fun ForgotPasswordScreen(
onClick = { focusManager.clearFocus(); viewModel.sendReset() }, onClick = { focusManager.clearFocus(); viewModel.sendReset() },
enabled = !state.isLoading, enabled = !state.isLoading,
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary) colors = ButtonDefaults.buttonColors(
containerColor = AuthPrimary,
contentColor = AuthOnPrimary
)
) { ) {
if (state.isLoading) CircularProgressIndicator( if (state.isLoading) CircularProgressIndicator(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
color = MaterialTheme.colorScheme.onPrimary, color = AuthOnPrimary,
strokeWidth = 2.dp strokeWidth = 2.dp
) )
else Text("Send reset email", style = MaterialTheme.typography.labelLarge) else Text("Send reset email", style = MaterialTheme.typography.labelLarge)

View File

@ -1,5 +1,7 @@
package com.couplesconnect.app.ui.auth package com.couplesconnect.app.ui.auth
import androidx.compose.foundation.background
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -37,6 +39,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
@ -63,7 +66,11 @@ fun LoginScreen(
state.error?.let { snackbar.showSnackbar(it); viewModel.dismissError() } state.error?.let { snackbar.showSnackbar(it); viewModel.dismissError() }
} }
Scaffold(snackbarHost = { SnackbarHost(snackbar) }) { padding -> Scaffold(
snackbarHost = { SnackbarHost(snackbar) },
containerColor = Color.Transparent,
modifier = Modifier.background(AuthBackgroundBrush)
) { padding ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -80,14 +87,14 @@ fun LoginScreen(
Text( Text(
text = "Welcome back", text = "Welcome back",
style = MaterialTheme.typography.displaySmall, style = MaterialTheme.typography.displaySmall,
color = MaterialTheme.colorScheme.primary, color = AuthInk,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
Text( Text(
text = "Sign in to reconnect with your partner.", text = "Sign in to reconnect with your partner.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), color = AuthMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@ -99,6 +106,7 @@ fun LoginScreen(
label = { Text("Email") }, label = { Text("Email") },
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = authTextFieldColors(),
keyboardOptions = KeyboardOptions( keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Email, keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next imeAction = ImeAction.Next
@ -114,6 +122,7 @@ fun LoginScreen(
label = { Text("Password") }, label = { Text("Password") },
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = authTextFieldColors(),
visualTransformation = if (state.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (state.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions( keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password, keyboardType = KeyboardType.Password,
@ -135,7 +144,11 @@ fun LoginScreen(
onClick = { onNavigate(AppRoute.FORGOT_PASSWORD) }, onClick = { onNavigate(AppRoute.FORGOT_PASSWORD) },
modifier = Modifier.align(Alignment.End) modifier = Modifier.align(Alignment.End)
) { ) {
Text("Forgot password?", style = MaterialTheme.typography.bodySmall) Text(
"Forgot password?",
style = MaterialTheme.typography.bodySmall,
color = AuthPrimaryDeep
)
} }
Spacer(Modifier.height(20.dp)) Spacer(Modifier.height(20.dp))
@ -144,9 +157,12 @@ fun LoginScreen(
onClick = { focusManager.clearFocus(); viewModel.signIn() }, onClick = { focusManager.clearFocus(); viewModel.signIn() },
enabled = !state.isLoading, enabled = !state.isLoading,
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary) colors = ButtonDefaults.buttonColors(
containerColor = AuthPrimary,
contentColor = AuthOnPrimary
)
) { ) {
if (state.isLoading) CircularProgressIndicator(color = MaterialTheme.colorScheme.onPrimary, strokeWidth = 2.dp) if (state.isLoading) CircularProgressIndicator(color = AuthOnPrimary, strokeWidth = 2.dp)
else Text("Sign in", style = MaterialTheme.typography.labelLarge) else Text("Sign in", style = MaterialTheme.typography.labelLarge)
} }
@ -155,7 +171,12 @@ fun LoginScreen(
OutlinedButton( OutlinedButton(
onClick = viewModel::signInAnonymously, onClick = viewModel::signInAnonymously,
enabled = !state.isLoading, enabled = !state.isLoading,
modifier = Modifier.fillMaxWidth().height(52.dp) modifier = Modifier.fillMaxWidth().height(52.dp),
colors = ButtonDefaults.outlinedButtonColors(
containerColor = Color.White.copy(alpha = 0.62f),
contentColor = AuthPrimaryDeep
),
border = BorderStroke(1.dp, AuthPrimaryDeep.copy(alpha = 0.28f))
) { ) {
Text("Try without account", style = MaterialTheme.typography.labelLarge) Text("Try without account", style = MaterialTheme.typography.labelLarge)
} }
@ -166,7 +187,7 @@ fun LoginScreen(
Text( Text(
"Don't have an account? Sign up", "Don't have an account? Sign up",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary color = AuthPrimaryDeep
) )
} }

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.auth package com.couplesconnect.app.ui.auth
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -31,6 +32,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -39,6 +41,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
@ -68,14 +71,21 @@ fun SignUpScreen(
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(snackbar) }, snackbarHost = { SnackbarHost(snackbar) },
containerColor = Color.Transparent,
modifier = Modifier.background(AuthBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate(AppRoute.LOGIN) }) { IconButton(onClick = { onNavigate(AppRoute.LOGIN) }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = AuthInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -95,14 +105,14 @@ fun SignUpScreen(
Text( Text(
text = "Create your account", text = "Create your account",
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary, color = AuthInk,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
Text( Text(
text = "You'll set your name after signing up.", text = "You'll set your name after signing up.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), color = AuthMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@ -114,6 +124,7 @@ fun SignUpScreen(
label = { Text("Email") }, label = { Text("Email") },
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = authTextFieldColors(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email, imeAction = ImeAction.Next), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email, imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }) keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) })
) )
@ -124,6 +135,7 @@ fun SignUpScreen(
label = { Text("Password") }, label = { Text("Password") },
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = authTextFieldColors(),
visualTransformation = if (state.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (state.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Next), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }), keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }),
@ -135,7 +147,13 @@ fun SignUpScreen(
) )
} }
}, },
supportingText = { Text("At least 6 characters", style = MaterialTheme.typography.bodySmall) } supportingText = {
Text(
"At least 6 characters",
style = MaterialTheme.typography.bodySmall,
color = AuthMuted
)
}
) )
Spacer(Modifier.height(12.dp)) Spacer(Modifier.height(12.dp))
OutlinedTextField( OutlinedTextField(
@ -144,6 +162,7 @@ fun SignUpScreen(
label = { Text("Confirm password") }, label = { Text("Confirm password") },
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = authTextFieldColors(),
visualTransformation = if (state.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (state.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus(); viewModel.signUp() }) keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus(); viewModel.signUp() })
@ -155,9 +174,12 @@ fun SignUpScreen(
onClick = { focusManager.clearFocus(); viewModel.signUp() }, onClick = { focusManager.clearFocus(); viewModel.signUp() },
enabled = !state.isLoading, enabled = !state.isLoading,
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary) colors = ButtonDefaults.buttonColors(
containerColor = AuthPrimary,
contentColor = AuthOnPrimary
)
) { ) {
if (state.isLoading) CircularProgressIndicator(color = MaterialTheme.colorScheme.onPrimary, strokeWidth = 2.dp) if (state.isLoading) CircularProgressIndicator(color = AuthOnPrimary, strokeWidth = 2.dp)
else Text("Create account", style = MaterialTheme.typography.labelLarge) else Text("Create account", style = MaterialTheme.typography.labelLarge)
} }
@ -167,7 +189,7 @@ fun SignUpScreen(
Text( Text(
"Already have an account? Sign in", "Already have an account? Sign in",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary color = AuthPrimaryDeep
) )
} }

View File

@ -62,9 +62,9 @@ fun PlaceholderScreen(
) { ) {
val background = Brush.linearGradient( val background = Brush.linearGradient(
colors = listOf( colors = listOf(
Color(0xFFFFFBFA), Color(0xFFFFFBFE),
Color(0xFFF3F7F1), Color(0xFFF8F1FF),
Color(0xFFEAF0F4) Color(0xFFFFEEF7)
), ),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
@ -261,7 +261,7 @@ private fun PreviewPanel(
Text( Text(
text = title, text = title,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
color = Color(0xFF312B29), color = Color(0xFF261D2E),
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold
) )
Box( Box(
@ -273,7 +273,7 @@ private fun PreviewPanel(
Text( Text(
text = "Ready", text = "Ready",
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = Color(0xFF3E3734) color = Color(0xFF56306F)
) )
} }
} }
@ -299,7 +299,7 @@ private fun DetailRow(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(18.dp)) .clip(RoundedCornerShape(18.dp))
.background(Color(0xFFF9F6F2).copy(alpha = 0.86f)) .background(Color(0xFFFFF8FC))
.padding(14.dp), .padding(14.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@ -313,7 +313,7 @@ private fun DetailRow(
Text( Text(
text = (index + 1).toString().padStart(2, '0'), text = (index + 1).toString().padStart(2, '0'),
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
color = Color(0xFF3E3734), color = Color(0xFF56306F),
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold
) )
} }
@ -321,7 +321,7 @@ private fun DetailRow(
Text( Text(
text = detail, text = detail,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = Color(0xFF433B38), color = Color(0xFF5A5060),
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
} }
@ -333,7 +333,7 @@ private fun DepthBackdrop(accent: Color) {
rotate(degrees = -12f, pivot = Offset(size.width * 0.76f, size.height * 0.12f)) { rotate(degrees = -12f, pivot = Offset(size.width * 0.76f, size.height * 0.12f)) {
drawRoundRect( drawRoundRect(
brush = Brush.linearGradient( brush = Brush.linearGradient(
listOf(accent.copy(alpha = 0.28f), Color(0xFF81B29A).copy(alpha = 0.14f)) listOf(accent.copy(alpha = 0.26f), Color(0xFFE7A2D1).copy(alpha = 0.14f))
), ),
topLeft = Offset(size.width * 0.44f, -size.height * 0.05f), topLeft = Offset(size.width * 0.44f, -size.height * 0.05f),
size = Size(size.width * 0.78f, size.height * 0.24f), size = Size(size.width * 0.78f, size.height * 0.24f),
@ -343,7 +343,7 @@ private fun DepthBackdrop(accent: Color) {
rotate(degrees = 9f, pivot = Offset(size.width * 0.18f, size.height * 0.78f)) { rotate(degrees = 9f, pivot = Offset(size.width * 0.18f, size.height * 0.78f)) {
drawRoundRect( drawRoundRect(
brush = Brush.linearGradient( brush = Brush.linearGradient(
listOf(Color(0xFFF2CC8F).copy(alpha = 0.24f), Color.White.copy(alpha = 0.08f)) listOf(Color(0xFFF4E8FF).copy(alpha = 0.32f), Color.White.copy(alpha = 0.08f))
), ),
topLeft = Offset(-size.width * 0.22f, size.height * 0.64f), topLeft = Offset(-size.width * 0.22f, size.height * 0.64f),
size = Size(size.width * 0.74f, size.height * 0.22f), size = Size(size.width * 0.74f, size.height * 0.22f),

View File

@ -31,7 +31,7 @@ import androidx.compose.ui.unit.sp
private val Purple = Color(0xFF5F3A87) private val Purple = Color(0xFF5F3A87)
private val PurpleLight = Color(0xFFF0EDF9) private val PurpleLight = Color(0xFFF0EDF9)
private val GreenPill = Color(0xFF81B29A) private val PinkPill = Color(0xFFB98AF4)
@Composable @Composable
fun SpecialDatesSection( fun SpecialDatesSection(
@ -187,7 +187,7 @@ private fun DateBlock(
private fun TodayPill() { private fun TodayPill() {
Surface( Surface(
shape = RoundedCornerShape(999.dp), shape = RoundedCornerShape(999.dp),
color = GreenPill color = PinkPill
) { ) {
Text( Text(
text = "Today", text = "Today",
@ -215,7 +215,7 @@ private fun DateCountPill() {
} }
} }
@Preview(showBackground = true, backgroundColor = 0xFFFFFBFA) @Preview(showBackground = true, backgroundColor = 0xFFFFFBFE)
@Composable @Composable
fun SpecialDatesSectionPreview() { fun SpecialDatesSectionPreview() {
SpecialDatesSection() SpecialDatesSection()

View File

@ -17,7 +17,7 @@ fun PartnerHomeScreen(
description = "A partner-aware view for pairing status, recent rituals, and the next shared prompt.", description = "A partner-aware view for pairing status, recent rituals, and the next shared prompt.",
route = AppRoute.PARTNER_HOME, route = AppRoute.PARTNER_HOME,
onNavigate = onNavigate, onNavigate = onNavigate,
accent = Color(0xFF81B29A), accent = Color(0xFFB98AF4),
primaryAction = PlaceholderAction("Invite partner", AppRoute.CREATE_INVITE), primaryAction = PlaceholderAction("Invite partner", AppRoute.CREATE_INVITE),
secondaryAction = PlaceholderAction("Home", AppRoute.HOME), secondaryAction = PlaceholderAction("Home", AppRoute.HOME),
chips = listOf("Partner state", "Pairing bridge", "Shared rhythm"), chips = listOf("Partner state", "Pairing bridge", "Shared rhythm"),

View File

@ -50,9 +50,9 @@ fun OnboardingScreen(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
colors = listOf(Color(0xFFFFF8F5), Color(0xFFF5EDE8)), colors = listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset(0f, 0f), start = Offset.Zero,
end = Offset(0f, Float.POSITIVE_INFINITY) end = Offset.Infinite
) )
) )
) { ) {

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.pairing package com.couplesconnect.app.ui.pairing
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -30,6 +31,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -37,6 +39,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardCapitalization
@ -45,6 +48,13 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.couplesconnect.app.core.navigation.AppRoute import com.couplesconnect.app.core.navigation.AppRoute
import com.couplesconnect.app.ui.settings.SettingsBackgroundBrush
import com.couplesconnect.app.ui.settings.SettingsDanger
import com.couplesconnect.app.ui.settings.SettingsInk
import com.couplesconnect.app.ui.settings.SettingsMuted
import com.couplesconnect.app.ui.settings.SettingsOnPrimary
import com.couplesconnect.app.ui.settings.SettingsPrimary
import com.couplesconnect.app.ui.settings.SettingsPrimaryDeep
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -62,14 +72,21 @@ fun AcceptInviteScreen(
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(snackbar) }, snackbarHost = { SnackbarHost(snackbar) },
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate(AppRoute.CREATE_INVITE) }) { IconButton(onClick = { onNavigate(AppRoute.CREATE_INVITE) }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = SettingsInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -89,14 +106,14 @@ fun AcceptInviteScreen(
Text( Text(
"Enter the code", "Enter the code",
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary, color = SettingsInk,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
Text( Text(
"Ask your partner to share their 6-character invite code.", "Ask your partner to share their 6-character invite code.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), color = SettingsMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@ -109,7 +126,7 @@ fun AcceptInviteScreen(
placeholder = { Text("ABC123") }, placeholder = { Text("ABC123") },
singleLine = true, singleLine = true,
isError = state.error != null, isError = state.error != null,
supportingText = state.error?.let { error -> { Text(error, color = MaterialTheme.colorScheme.error) } }, supportingText = state.error?.let { error -> { Text(error, color = SettingsDanger) } },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
textStyle = MaterialTheme.typography.headlineSmall.copy( textStyle = MaterialTheme.typography.headlineSmall.copy(
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
@ -129,11 +146,14 @@ fun AcceptInviteScreen(
onClick = { focusManager.clearFocus(); viewModel.lookupCode() }, onClick = { focusManager.clearFocus(); viewModel.lookupCode() },
enabled = !state.isLoading && state.code.length == 6, enabled = !state.isLoading && state.code.length == 6,
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary) colors = ButtonDefaults.buttonColors(
containerColor = SettingsPrimary,
contentColor = SettingsOnPrimary
)
) { ) {
if (state.isLoading) CircularProgressIndicator( if (state.isLoading) CircularProgressIndicator(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
color = MaterialTheme.colorScheme.onPrimary, color = SettingsOnPrimary,
strokeWidth = 2.dp strokeWidth = 2.dp
) )
else Text("Continue", style = MaterialTheme.typography.labelLarge) else Text("Continue", style = MaterialTheme.typography.labelLarge)
@ -145,7 +165,7 @@ fun AcceptInviteScreen(
Text( Text(
"Need to create an invite instead?", "Need to create an invite instead?",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary color = SettingsPrimaryDeep
) )
} }
} }

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.pairing package com.couplesconnect.app.ui.pairing
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -32,6 +33,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -40,12 +42,20 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.couplesconnect.app.core.navigation.AppRoute import com.couplesconnect.app.core.navigation.AppRoute
import com.couplesconnect.app.ui.settings.SettingsBackgroundBrush
import com.couplesconnect.app.ui.settings.SettingsInk
import com.couplesconnect.app.ui.settings.SettingsMuted
import com.couplesconnect.app.ui.settings.SettingsOnPrimary
import com.couplesconnect.app.ui.settings.SettingsPrimary
import com.couplesconnect.app.ui.settings.SettingsPrimaryDeep
import com.couplesconnect.app.ui.settings.SettingsSoft
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -69,14 +79,21 @@ fun CreateInviteScreen(
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(snackbar) }, snackbarHost = { SnackbarHost(snackbar) },
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { IconButton(onClick = onBack) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = SettingsInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -98,14 +115,14 @@ fun CreateInviteScreen(
Text( Text(
"Invite your person", "Invite your person",
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary, color = SettingsInk,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
Text( Text(
"Share this code with your partner. They'll enter it to connect.", "Share this code with your partner. They'll enter it to connect.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), color = SettingsMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@ -114,7 +131,7 @@ fun CreateInviteScreen(
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primaryContainer containerColor = SettingsSoft
), ),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp) elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) { ) {
@ -127,7 +144,7 @@ fun CreateInviteScreen(
Text( Text(
text = state.inviteCode!!.chunked(3).joinToString(" "), text = state.inviteCode!!.chunked(3).joinToString(" "),
style = MaterialTheme.typography.displaySmall, style = MaterialTheme.typography.displaySmall,
color = MaterialTheme.colorScheme.onPrimaryContainer, color = SettingsPrimaryDeep,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
} }
@ -141,7 +158,10 @@ fun CreateInviteScreen(
scope.launch { snackbar.showSnackbar("Code copied!") } scope.launch { snackbar.showSnackbar("Code copied!") }
}, },
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary) colors = ButtonDefaults.buttonColors(
containerColor = SettingsPrimary,
contentColor = SettingsOnPrimary
)
) { ) {
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
@ -158,7 +178,7 @@ fun CreateInviteScreen(
Text( Text(
"Code expires in 24 hours", "Code expires in 24 hours",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.45f), color = SettingsMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@ -168,7 +188,7 @@ fun CreateInviteScreen(
Text( Text(
"Partner already has a code? Accept instead", "Partner already has a code? Accept instead",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary color = SettingsPrimaryDeep
) )
} }

View File

@ -17,7 +17,7 @@ fun EmailInviteScreen(
description = "Invite your partner with a clear message and a simple code.", description = "Invite your partner with a clear message and a simple code.",
route = AppRoute.EMAIL_INVITE, route = AppRoute.EMAIL_INVITE,
onNavigate = onNavigate, onNavigate = onNavigate,
accent = Color(0xFF6C8EA4), accent = Color(0xFFB98AF4),
primaryAction = PlaceholderAction("Confirm code", AppRoute.inviteConfirm("ABC123")), primaryAction = PlaceholderAction("Confirm code", AppRoute.inviteConfirm("ABC123")),
secondaryAction = PlaceholderAction("Create invite", AppRoute.CREATE_INVITE), secondaryAction = PlaceholderAction("Create invite", AppRoute.CREATE_INVITE),
chips = listOf("Email", "Code ABC123", "Invite"), chips = listOf("Email", "Code ABC123", "Invite"),

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.pairing package com.couplesconnect.app.ui.pairing
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -26,6 +27,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -33,10 +35,17 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.couplesconnect.app.core.navigation.AppRoute import com.couplesconnect.app.core.navigation.AppRoute
import com.couplesconnect.app.ui.settings.SettingsBackgroundBrush
import com.couplesconnect.app.ui.settings.SettingsInk
import com.couplesconnect.app.ui.settings.SettingsMuted
import com.couplesconnect.app.ui.settings.SettingsOnPrimary
import com.couplesconnect.app.ui.settings.SettingsPrimary
import com.couplesconnect.app.ui.settings.SettingsPrimaryDeep
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -57,14 +66,21 @@ fun InviteConfirmScreen(
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(snackbar) }, snackbarHost = { SnackbarHost(snackbar) },
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate(AppRoute.ACCEPT_INVITE) }) { IconButton(onClick = { onNavigate(AppRoute.ACCEPT_INVITE) }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = SettingsInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -86,7 +102,7 @@ fun InviteConfirmScreen(
Text( Text(
"", "",
style = MaterialTheme.typography.displayMedium, style = MaterialTheme.typography.displayMedium,
color = MaterialTheme.colorScheme.primary color = SettingsPrimaryDeep
) )
Spacer(Modifier.height(20.dp)) Spacer(Modifier.height(20.dp))
@ -94,14 +110,14 @@ fun InviteConfirmScreen(
Text( Text(
"Pair with ${state.inviterName}?", "Pair with ${state.inviterName}?",
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary, color = SettingsInk,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Spacer(Modifier.height(12.dp)) Spacer(Modifier.height(12.dp))
Text( Text(
"Once you confirm, you'll be connected and can start exploring questions together.", "Once you confirm, you'll be connected and can start exploring questions together.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), color = SettingsMuted,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@ -110,7 +126,7 @@ fun InviteConfirmScreen(
Text( Text(
"Code: $inviteCode", "Code: $inviteCode",
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.4f) color = SettingsMuted
) )
Spacer(Modifier.height(32.dp)) Spacer(Modifier.height(32.dp))
@ -119,11 +135,14 @@ fun InviteConfirmScreen(
onClick = viewModel::confirmPairing, onClick = viewModel::confirmPairing,
enabled = !state.isConfirming, enabled = !state.isConfirming,
modifier = Modifier.fillMaxWidth().height(56.dp), modifier = Modifier.fillMaxWidth().height(56.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary) colors = ButtonDefaults.buttonColors(
containerColor = SettingsPrimary,
contentColor = SettingsOnPrimary
)
) { ) {
if (state.isConfirming) CircularProgressIndicator( if (state.isConfirming) CircularProgressIndicator(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
color = MaterialTheme.colorScheme.onPrimary, color = SettingsOnPrimary,
strokeWidth = 2.dp strokeWidth = 2.dp
) )
else Text("Pair up", style = MaterialTheme.typography.labelLarge) else Text("Pair up", style = MaterialTheme.typography.labelLarge)
@ -135,7 +154,7 @@ fun InviteConfirmScreen(
Text( Text(
"That's not right — go back", "That's not right — go back",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary color = SettingsPrimaryDeep
) )
} }

View File

@ -55,7 +55,7 @@ fun PaywallScreen(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF4ECFF), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )

View File

@ -77,7 +77,7 @@ private fun QuestionCategoryContent(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF3F7F1), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )

View File

@ -17,7 +17,7 @@ fun QuestionComposerScreen(
description = "Shape your own prompt with a tone that feels generous and clear.", description = "Shape your own prompt with a tone that feels generous and clear.",
route = AppRoute.QUESTION_COMPOSER, route = AppRoute.QUESTION_COMPOSER,
onNavigate = onNavigate, onNavigate = onNavigate,
accent = Color(0xFF81B29A), accent = Color(0xFFB98AF4),
primaryAction = PlaceholderAction("Open thread", AppRoute.questionThread("couple", "custom")), primaryAction = PlaceholderAction("Open thread", AppRoute.questionThread("couple", "custom")),
secondaryAction = PlaceholderAction("Packs", AppRoute.QUESTION_PACKS), secondaryAction = PlaceholderAction("Packs", AppRoute.QUESTION_PACKS),
chips = listOf("Custom prompt", "Tone aware", "Save"), chips = listOf("Custom prompt", "Tone aware", "Save"),

View File

@ -88,7 +88,7 @@ private fun QuestionPackLibraryContent(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF1F6F3), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )

View File

@ -17,7 +17,7 @@ fun AccountScreen(
description = "Manage identity, sign-in, exports, and account choices in one calm place.", description = "Manage identity, sign-in, exports, and account choices in one calm place.",
route = AppRoute.ACCOUNT, route = AppRoute.ACCOUNT,
onNavigate = onNavigate, onNavigate = onNavigate,
accent = Color(0xFF6C8EA4), accent = Color(0xFFB98AF4),
primaryAction = PlaceholderAction("Notifications", AppRoute.NOTIFICATIONS), primaryAction = PlaceholderAction("Notifications", AppRoute.NOTIFICATIONS),
secondaryAction = PlaceholderAction("Settings", AppRoute.SETTINGS), secondaryAction = PlaceholderAction("Settings", AppRoute.SETTINGS),
chips = listOf("Identity", "Export", "Account care"), chips = listOf("Identity", "Export", "Account care"),

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.settings package com.couplesconnect.app.ui.settings
import androidx.compose.foundation.background
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.couplesconnect.app.core.navigation.AppRoute import com.couplesconnect.app.core.navigation.AppRoute
@ -39,6 +40,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -111,7 +113,10 @@ fun DeleteAccountScreen(
confirmButton = { confirmButton = {
Button( Button(
onClick = viewModel::confirmDelete, onClick = viewModel::confirmDelete,
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error) colors = ButtonDefaults.buttonColors(
containerColor = SettingsDanger,
contentColor = Color.White
)
) { ) {
Text("Delete", color = Color.White) Text("Delete", color = Color.White)
} }
@ -123,14 +128,21 @@ fun DeleteAccountScreen(
} }
Scaffold( Scaffold(
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Delete account") }, title = { Text("Delete account", color = SettingsInk) },
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate("back") }) { IconButton(onClick = { onNavigate("back") }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = SettingsInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -147,19 +159,19 @@ fun DeleteAccountScreen(
Text( Text(
text = "Deleting your account is permanent and cannot be reversed. Your profile, sign-in, and pairing will be removed immediately.", text = "Deleting your account is permanent and cannot be reversed. Your profile, sign-in, and pairing will be removed immediately.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
Text( Text(
text = "Your partner will be unpaired and can start fresh.", text = "Your partner will be unpaired and can start fresh.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
state.error?.let { err -> state.error?.let { err ->
Text( Text(
text = err, text = err,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error color = SettingsDanger
) )
} }
@ -170,7 +182,10 @@ fun DeleteAccountScreen(
enabled = !state.isDeleting, enabled = !state.isDeleting,
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
shape = androidx.compose.foundation.shape.RoundedCornerShape(12.dp), shape = androidx.compose.foundation.shape.RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error) colors = ButtonDefaults.buttonColors(
containerColor = SettingsDanger,
contentColor = Color.White
)
) { ) {
if (state.isDeleting) { if (state.isDeleting) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {

View File

@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@ -34,9 +35,9 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -86,14 +87,21 @@ fun NotificationSettingsScreen(
val state by viewModel.uiState.collectAsState() val state by viewModel.uiState.collectAsState()
Scaffold( Scaffold(
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Notifications") }, title = { Text("Notifications", color = SettingsInk) },
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate("back") }) { IconButton(onClick = { onNavigate("back") }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = SettingsInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -110,14 +118,14 @@ fun NotificationSettingsScreen(
Text( Text(
text = "Reminders", text = "Reminders",
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = SettingsMuted,
modifier = Modifier.padding(horizontal = 4.dp, vertical = 4.dp) modifier = Modifier.padding(horizontal = 4.dp, vertical = 4.dp)
) )
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) colors = CardDefaults.cardColors(containerColor = SettingsCard)
) { ) {
Column { Column {
NotifToggleRow( NotifToggleRow(
@ -148,14 +156,14 @@ fun NotificationSettingsScreen(
Text( Text(
text = "Quiet hours", text = "Quiet hours",
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = SettingsMuted,
modifier = Modifier.padding(horizontal = 4.dp, vertical = 4.dp) modifier = Modifier.padding(horizontal = 4.dp, vertical = 4.dp)
) )
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) colors = CardDefaults.cardColors(containerColor = SettingsCard)
) { ) {
Column { Column {
NotifToggleRow( NotifToggleRow(
@ -172,7 +180,7 @@ fun NotificationSettingsScreen(
Text( Text(
text = "These preferences shape the reminders you see from the app.", text = "These preferences shape the reminders you see from the app.",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = SettingsMuted,
modifier = Modifier.padding(horizontal = 4.dp) modifier = Modifier.padding(horizontal = 4.dp)
) )
} }
@ -198,18 +206,18 @@ private fun NotifToggleRow(
text = label, text = label,
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface color = SettingsInk
) )
Text( Text(
text = description, text = description,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
} }
Switch( Switch(
checked = checked, checked = checked,
onCheckedChange = onCheckedChange, onCheckedChange = onCheckedChange,
colors = SwitchDefaults.colors(checkedThumbColor = Color(0xFFB98AF4), checkedTrackColor = Color(0xFFB98AF4).copy(alpha = 0.4f)) colors = settingsSwitchColors()
) )
} }
} }

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.settings package com.couplesconnect.app.ui.settings
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -26,6 +27,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -44,14 +46,21 @@ fun PrivacyScreen(
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
Scaffold( Scaffold(
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Privacy & Terms") }, title = { Text("Privacy & Terms", color = SettingsInk) },
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate("back") }) { IconButton(onClick = { onNavigate("back") }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = SettingsInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -68,13 +77,13 @@ fun PrivacyScreen(
Text( Text(
text = "Your data stays between the two of you. These documents explain exactly what we collect, how we use it, and what rights you have.", text = "Your data stays between the two of you. These documents explain exactly what we collect, how we use it, and what rights you have.",
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) colors = CardDefaults.cardColors(containerColor = SettingsCard)
) { ) {
Column { Column {
LegalLinkRow( LegalLinkRow(
@ -106,7 +115,7 @@ fun PrivacyScreen(
Text( Text(
text = "Answer text and messages are private by design and are never shared with third parties.", text = "Answer text and messages are private by design and are never shared with third parties.",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = SettingsMuted,
modifier = Modifier.padding(horizontal = 4.dp) modifier = Modifier.padding(horizontal = 4.dp)
) )
} }
@ -132,19 +141,19 @@ private fun LegalLinkRow(
text = label, text = label,
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface color = SettingsInk
) )
Text( Text(
text = description, text = description,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
} }
Icon( Icon(
Icons.AutoMirrored.Filled.OpenInNew, Icons.AutoMirrored.Filled.OpenInNew,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
tint = Color(0xFF81B29A) tint = SettingsPrimaryDeep
) )
} }
} }

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.settings package com.couplesconnect.app.ui.settings
import androidx.compose.foundation.background
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.couplesconnect.app.core.navigation.AppRoute import com.couplesconnect.app.core.navigation.AppRoute
@ -39,6 +40,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -108,7 +110,10 @@ fun RelationshipSettingsScreen(
confirmButton = { confirmButton = {
Button( Button(
onClick = viewModel::confirmLeave, onClick = viewModel::confirmLeave,
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error) colors = ButtonDefaults.buttonColors(
containerColor = SettingsDanger,
contentColor = Color.White
)
) { ) {
Text("Leave", color = Color.White) Text("Leave", color = Color.White)
} }
@ -120,14 +125,21 @@ fun RelationshipSettingsScreen(
} }
Scaffold( Scaffold(
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Relationship") }, title = { Text("Relationship", color = SettingsInk) },
navigationIcon = { navigationIcon = {
IconButton(onClick = { onNavigate("back") }) { IconButton(onClick = { onNavigate("back") }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = SettingsInk
)
} }
} },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
) )
} }
) { padding -> ) { padding ->
@ -144,14 +156,14 @@ fun RelationshipSettingsScreen(
Text( Text(
text = "Your relationship data stays private. Leaving unlinks you and your partner — it does not delete your account or answers.", text = "Your relationship data stays private. Leaving unlinks you and your partner — it does not delete your account or answers.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
state.error?.let { err -> state.error?.let { err ->
Text( Text(
text = err, text = err,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error color = SettingsDanger
) )
} }
@ -162,7 +174,10 @@ fun RelationshipSettingsScreen(
enabled = !state.isLeaving, enabled = !state.isLeaving,
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
shape = androidx.compose.foundation.shape.RoundedCornerShape(12.dp), shape = androidx.compose.foundation.shape.RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error) colors = ButtonDefaults.buttonColors(
containerColor = SettingsDanger,
contentColor = Color.White
)
) { ) {
if (state.isLeaving) { if (state.isLeaving) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {

View File

@ -1,5 +1,6 @@
package com.couplesconnect.app.ui.settings package com.couplesconnect.app.ui.settings
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -37,6 +38,7 @@ import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -63,8 +65,19 @@ fun SettingsScreen(
} }
Scaffold( Scaffold(
containerColor = Color.Transparent,
modifier = Modifier.background(SettingsBackgroundBrush),
topBar = { topBar = {
TopAppBar(title = { Text("Settings", style = MaterialTheme.typography.titleLarge) }) TopAppBar(
title = {
Text(
"Settings",
style = MaterialTheme.typography.titleLarge,
color = SettingsInk
)
},
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
)
} }
) { padding -> ) { padding ->
if (state.isLoading) { if (state.isLoading) {
@ -96,7 +109,7 @@ fun SettingsScreen(
}, },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) colors = CardDefaults.cardColors(containerColor = SettingsCard)
) { ) {
Row( Row(
modifier = Modifier.padding(16.dp), modifier = Modifier.padding(16.dp),
@ -107,20 +120,20 @@ fun SettingsScreen(
Icons.Filled.Person, Icons.Filled.Person,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(40.dp), modifier = Modifier.size(40.dp),
tint = MaterialTheme.colorScheme.primary tint = SettingsPrimaryDeep
) )
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
Text( Text(
text = state.displayName.ifBlank { "No name set" }, text = state.displayName.ifBlank { "No name set" },
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.onSurface color = SettingsInk
) )
if (state.email.isNotBlank()) { if (state.email.isNotBlank()) {
Text( Text(
text = state.email, text = state.email,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
} }
} }
@ -129,9 +142,15 @@ fun SettingsScreen(
// Partner card // Partner card
Card( Card(
onClick = {
onNavigate(
if (state.isPaired) AppRoute.RELATIONSHIP_SETTINGS
else AppRoute.CREATE_INVITE
)
},
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) colors = CardDefaults.cardColors(containerColor = SettingsCard)
) { ) {
Row( Row(
modifier = Modifier.padding(16.dp), modifier = Modifier.padding(16.dp),
@ -142,7 +161,7 @@ fun SettingsScreen(
if (state.isPaired) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder, if (state.isPaired) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(40.dp), modifier = Modifier.size(40.dp),
tint = if (state.isPaired) Color(0xFF5F3A87) else MaterialTheme.colorScheme.onSurfaceVariant tint = if (state.isPaired) SettingsPrimaryDeep else SettingsMuted
) )
Column( Column(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
@ -151,20 +170,20 @@ fun SettingsScreen(
Text( Text(
text = if (state.isPaired) "Connected with" else "No partner yet", text = if (state.isPaired) "Connected with" else "No partner yet",
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = SettingsMuted
) )
if (state.isPaired) { if (state.isPaired) {
Text( Text(
text = state.partnerName ?: "Your partner", text = state.partnerName ?: "Your partner",
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.onSurface color = SettingsInk
) )
} else { } else {
Text( Text(
text = "Invite someone to connect", text = "Invite someone to connect",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface color = SettingsInk
) )
} }
} }
@ -172,7 +191,7 @@ fun SettingsScreen(
Icons.AutoMirrored.Filled.ArrowForwardIos, Icons.AutoMirrored.Filled.ArrowForwardIos,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
tint = MaterialTheme.colorScheme.primary tint = SettingsPrimaryDeep
) )
} }
} }
@ -183,7 +202,7 @@ fun SettingsScreen(
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) colors = CardDefaults.cardColors(containerColor = SettingsCard)
) { ) {
Column { Column {
SettingsRow( SettingsRow(
@ -212,21 +231,21 @@ fun SettingsScreen(
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) colors = CardDefaults.cardColors(containerColor = SettingsCard)
) { ) {
Column { Column {
SettingsRow( SettingsRow(
icon = Icons.Filled.Favorite, icon = Icons.Filled.Favorite,
label = "Leave couple", label = "Leave couple",
onClick = { onNavigate(AppRoute.RELATIONSHIP_SETTINGS) }, onClick = { onNavigate(AppRoute.RELATIONSHIP_SETTINGS) },
tint = MaterialTheme.colorScheme.error tint = SettingsDanger
) )
Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 0.5.dp) Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 0.5.dp)
SettingsRow( SettingsRow(
icon = Icons.Filled.Warning, icon = Icons.Filled.Warning,
label = "Delete account", label = "Delete account",
onClick = { onNavigate(AppRoute.DELETE_ACCOUNT) }, onClick = { onNavigate(AppRoute.DELETE_ACCOUNT) },
tint = MaterialTheme.colorScheme.error tint = SettingsDanger
) )
} }
} }
@ -239,12 +258,12 @@ fun SettingsScreen(
modifier = Modifier.fillMaxWidth().height(52.dp), modifier = Modifier.fillMaxWidth().height(52.dp),
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colorScheme.error contentColor = SettingsDanger
) )
) { ) {
if (state.isSigningOut) CircularProgressIndicator( if (state.isSigningOut) CircularProgressIndicator(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
color = MaterialTheme.colorScheme.error, color = SettingsDanger,
strokeWidth = 2.dp strokeWidth = 2.dp
) )
else Text("Sign out", style = MaterialTheme.typography.labelLarge) else Text("Sign out", style = MaterialTheme.typography.labelLarge)
@ -261,7 +280,7 @@ private fun SettingsRow(
icon: ImageVector, icon: ImageVector,
label: String, label: String,
onClick: () -> Unit, onClick: () -> Unit,
tint: androidx.compose.ui.graphics.Color = MaterialTheme.colorScheme.onSurfaceVariant tint: androidx.compose.ui.graphics.Color = SettingsMuted
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@ -275,14 +294,14 @@ private fun SettingsRow(
Text( Text(
text = label, text = label,
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
color = if (tint == MaterialTheme.colorScheme.onSurfaceVariant) MaterialTheme.colorScheme.onSurface else tint, color = if (tint == SettingsMuted) SettingsInk else tint,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
Icon( Icon(
Icons.AutoMirrored.Filled.ArrowForwardIos, Icons.AutoMirrored.Filled.ArrowForwardIos,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(14.dp), modifier = Modifier.size(14.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant tint = SettingsMuted
) )
} }
} }

View File

@ -0,0 +1,31 @@
package com.couplesconnect.app.ui.settings
import androidx.compose.material3.SwitchDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
internal val SettingsBackgroundBrush: Brush
get() = Brush.linearGradient(
colors = listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero,
end = Offset.Infinite
)
internal val SettingsInk = Color(0xFF261D2E)
internal val SettingsMuted = Color(0xFF5A5060)
internal val SettingsPrimary = Color(0xFFB98AF4)
internal val SettingsPrimaryDeep = Color(0xFF56306F)
internal val SettingsOnPrimary = Color(0xFF24122F)
internal val SettingsCard = Color.White
internal val SettingsSoft = Color(0xFFF4E8FF)
internal val SettingsDanger = Color(0xFF8D2D35)
@Composable
internal fun settingsSwitchColors() = SwitchDefaults.colors(
checkedThumbColor = SettingsPrimary,
checkedTrackColor = SettingsPrimary.copy(alpha = 0.42f),
uncheckedThumbColor = SettingsMuted.copy(alpha = 0.72f),
uncheckedTrackColor = SettingsMuted.copy(alpha = 0.16f)
)

View File

@ -5,16 +5,16 @@ import androidx.compose.ui.graphics.Color
// Dark theme colors (for reference if needed) // Dark theme colors (for reference if needed)
val darkPrimaryColor = Color(0xFF8F5FC8) val darkPrimaryColor = Color(0xFF8F5FC8)
val darkPrimaryContainerColor = Color(0xFF43255F) val darkPrimaryContainerColor = Color(0xFF43255F)
val darkSecondaryColor = Color(0xFF81B29A) val darkSecondaryColor = Color(0xFFFFAFD9)
val darkTertiaryColor = Color(0xFFF2CC8F) val darkTertiaryColor = Color(0xFFB98AF4)
val darkBackgroundColor = Color(0xFF1F1F1F) val darkBackgroundColor = Color(0xFF18111E)
val darkSurfaceColor = Color(0xFF2D2D2D) val darkSurfaceColor = Color(0xFF211729)
val darkErrorColor = Color(0xFFE76F51) val darkErrorColor = Color(0xFFFFB3BA)
val darkOnPrimaryColor = Color(0xFFFFFFFF) val darkOnPrimaryColor = Color(0xFFFFFFFF)
val darkOnPrimaryContainerColor = Color(0xFFF3E8FF) val darkOnPrimaryContainerColor = Color(0xFFF3E8FF)
val darkOnSecondaryColor = Color(0xFFFFFFFF) val darkOnSecondaryColor = Color(0xFFFFFFFF)
val darkOnTertiaryColor = Color(0xFF3E3E3E) val darkOnTertiaryColor = Color(0xFF24122F)
val darkOnBackgroundColor = Color(0xFFE0E0E0) val darkOnBackgroundColor = Color(0xFFF2E8F6)
val darkOnSurfaceColor = Color(0xFFE0E0E0) val darkOnSurfaceColor = Color(0xFFF2E8F6)
val darkOnErrorColor = Color(0xFFFFFFFF) val darkOnErrorColor = Color(0xFFFFFFFF)

View File

@ -24,18 +24,18 @@ fun CouplesConnectTheme(
// Purple-pink color palette (Light theme) // Purple-pink color palette (Light theme)
val PrimaryColor = Color(0xFF8F5FC8) val PrimaryColor = Color(0xFF8F5FC8)
val PrimaryContainerColor = Color(0xFFF3E8FF) val PrimaryContainerColor = Color(0xFFF3E8FF)
val SecondaryColor = Color(0xFF81B29A) val SecondaryColor = Color(0xFFE7A2D1)
val TertiaryColor = Color(0xFFF2CC8F) val TertiaryColor = Color(0xFFB98AF4)
val BackgroundColor = Color(0xFFFFFBFA) val BackgroundColor = Color(0xFFFFFBFE)
val SurfaceColor = Color(0xFFFFFBFA) val SurfaceColor = Color(0xFFFFFBFE)
val ErrorColor = Color(0xFFE76F51) val ErrorColor = Color(0xFF8D2D35)
val OnPrimaryColor = Color(0xFFFFFFFF) val OnPrimaryColor = Color(0xFF24122F)
val OnPrimaryContainerColor = Color(0xFF321545) val OnPrimaryContainerColor = Color(0xFF321545)
val OnSecondaryColor = Color(0xFFFFFFFF) val OnSecondaryColor = Color(0xFF2E1731)
val OnTertiaryColor = Color(0xFF3E3E3E) val OnTertiaryColor = Color(0xFF24122F)
val OnBackgroundColor = Color(0xFF3E3E3E) val OnBackgroundColor = Color(0xFF261D2E)
val OnSurfaceColor = Color(0xFF3E3E3E) val OnSurfaceColor = Color(0xFF261D2E)
val OnErrorColor = Color(0xFFFFFFFF) val OnErrorColor = Color(0xFFFFFFFF)
val lightColors = lightColorScheme( val lightColors = lightColorScheme(
@ -56,18 +56,18 @@ val lightColors = lightColorScheme(
) )
val darkColors = darkColorScheme( val darkColors = darkColorScheme(
primary = PrimaryColor, primary = Color(0xFFCFA7FF),
onPrimary = OnPrimaryColor, onPrimary = Color(0xFF2A1238),
primaryContainer = PrimaryContainerColor, primaryContainer = Color(0xFF43255F),
onPrimaryContainer = OnPrimaryContainerColor, onPrimaryContainer = Color(0xFFF3E8FF),
secondary = SecondaryColor, secondary = Color(0xFFFFAFD9),
onSecondary = OnSecondaryColor, onSecondary = Color(0xFF3B1730),
tertiary = TertiaryColor, tertiary = Color(0xFFB98AF4),
onTertiary = OnTertiaryColor, onTertiary = Color(0xFF24122F),
background = Color(0xFF1F1F1F), background = Color(0xFF18111E),
surface = Color(0xFF2D2D2D), surface = Color(0xFF211729),
onBackground = Color(0xFFE0E0E0), onBackground = Color(0xFFF2E8F6),
onSurface = Color(0xFFE0E0E0), onSurface = Color(0xFFF2E8F6),
error = ErrorColor, error = Color(0xFFFFB3BA),
onError = OnErrorColor onError = OnErrorColor
) )

View File

@ -68,7 +68,7 @@ private fun CategoryPickerContent(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF0EEF8), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )

View File

@ -86,7 +86,7 @@ private fun SpinWheelContent(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF0EEF8), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@ -143,7 +143,7 @@ private fun SpinWheelContent(
Text( Text(
text = if (state.spunAndReady) "" else "", text = if (state.spunAndReady) "" else "",
fontSize = 64.sp, fontSize = 64.sp,
color = if (state.spunAndReady) Color(0xFF81B29A) else Color(0xFF5F3A87) color = if (state.spunAndReady) Color(0xFFB98AF4) else Color(0xFF5F3A87)
) )
} }
} }

View File

@ -102,7 +102,7 @@ private fun WheelCompleteContent(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF0F5F2), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@ -121,7 +121,7 @@ private fun WheelCompleteContent(
Text( Text(
text = "", text = "",
fontSize = 64.sp, fontSize = 64.sp,
color = Color(0xFF81B29A) color = Color(0xFFB98AF4)
) )
Column( Column(
@ -159,7 +159,7 @@ private fun WheelCompleteContent(
Text( Text(
text = "$answered", text = "$answered",
style = MaterialTheme.typography.displaySmall.copy(fontWeight = FontWeight.SemiBold), style = MaterialTheme.typography.displaySmall.copy(fontWeight = FontWeight.SemiBold),
color = Color(0xFF81B29A) color = Color(0xFFB98AF4)
) )
Text( Text(
text = "of $total questions", text = "of $total questions",
@ -178,7 +178,7 @@ private fun WheelCompleteContent(
onClick = onHome, onClick = onHome,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(18.dp), shape = RoundedCornerShape(18.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF81B29A)) colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFB98AF4))
) { ) {
Text("Back home", color = Color.White) Text("Back home", color = Color.White)
} }

View File

@ -75,7 +75,7 @@ fun WheelHistoryScreen(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF0F5F2), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@ -157,7 +157,7 @@ private fun WheelSessionCard(session: QuestionSession) {
Text( Text(
text = SimpleDateFormat("d MMM", Locale.getDefault()).format(Date(ts)), text = SimpleDateFormat("d MMM", Locale.getDefault()).format(Date(ts)),
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
color = Color(0xFF81B29A) color = Color(0xFFB98AF4)
) )
} }
} }
@ -179,13 +179,13 @@ private fun WheelHistoryLockedCard(onUnlock: () -> Unit) {
) { ) {
Surface( Surface(
shape = RoundedCornerShape(50.dp), shape = RoundedCornerShape(50.dp),
color = Color(0xFFF0F5F2) color = Color(0xFFF8F1FF)
) { ) {
Icon( Icon(
Icons.Filled.Lock, Icons.Filled.Lock,
contentDescription = null, contentDescription = null,
modifier = Modifier.padding(16.dp).size(28.dp), modifier = Modifier.padding(16.dp).size(28.dp),
tint = Color(0xFF81B29A) tint = Color(0xFFB98AF4)
) )
} }
Text( Text(

View File

@ -72,7 +72,7 @@ private fun WheelSessionContent(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF3F0F8), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFE), Color(0xFFF8F1FF), Color(0xFFFFEEF7)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )