fix(theme): apply consistent color system, polish UI across all screens

This commit is contained in:
null 2026-06-16 02:49:36 -05:00
parent 5bb64f2421
commit e35f990755
21 changed files with 437 additions and 121 deletions

View File

@ -2,15 +2,22 @@ package com.couplesconnect.app.core.navigation
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Done
import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Star import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
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.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -20,6 +27,7 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.navArgument import androidx.navigation.navArgument
import com.couplesconnect.app.ui.auth.ForgotPasswordScreen import com.couplesconnect.app.ui.auth.ForgotPasswordScreen
import com.couplesconnect.app.ui.answers.AnswerHistoryScreen import com.couplesconnect.app.ui.answers.AnswerHistoryScreen
@ -53,6 +61,7 @@ import com.couplesconnect.app.ui.wheel.WheelCompleteScreen
import com.couplesconnect.app.ui.wheel.WheelHistoryScreen import com.couplesconnect.app.ui.wheel.WheelHistoryScreen
import com.couplesconnect.app.ui.wheel.WheelSessionScreen import com.couplesconnect.app.ui.wheel.WheelSessionScreen
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun AppNavigation( fun AppNavigation(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -61,17 +70,54 @@ fun AppNavigation(
val navController = rememberNavController() val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route val currentRoute = navBackStackEntry?.destination?.route
val bottomRoutes = topLevelRoutes.map { it.route }.toSet() val bottomRoutes = AppRoute.topLevelRoutes
val shellTitle = currentRoute
?.takeIf { it in shellBackRoutes }
?.let(AppRoute::titleFor)
val navigateRoute: (String) -> Unit = { route ->
if (route == "back") {
navController.popBackStack()
} else {
navController.navigate(route)
}
}
Scaffold( Scaffold(
modifier = modifier, modifier = modifier,
topBar = {
if (shellTitle != null) {
TopAppBar(
title = {
Text(
text = shellTitle,
style = MaterialTheme.typography.titleLarge
)
},
navigationIcon = {
IconButton(onClick = { navController.popBackStack() }) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back"
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.96f)
)
)
}
},
bottomBar = { bottomBar = {
if (currentRoute in bottomRoutes) { if (currentRoute in bottomRoutes) {
AppBottomNavigation( AppBottomNavigation(
currentRoute = currentRoute, currentRoute = currentRoute,
onRouteSelected = { route -> onRouteSelected = { route ->
navController.navigate(route) { navController.navigate(route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true launchSingleTop = true
restoreState = true
} }
} }
) )
@ -85,37 +131,37 @@ fun AppNavigation(
) { ) {
// Onboarding // Onboarding
composable(route = AppRoute.ONBOARDING) { composable(route = AppRoute.ONBOARDING) {
OnboardingScreen(onNavigate = navController::navigate) OnboardingScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.CREATE_PROFILE) { composable(route = AppRoute.CREATE_PROFILE) {
CreateProfileScreen(onNavigate = navController::navigate) CreateProfileScreen(onNavigate = navigateRoute)
} }
// Auth // Auth
composable(route = AppRoute.LOGIN) { composable(route = AppRoute.LOGIN) {
LoginScreen(onNavigate = navController::navigate) LoginScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.SIGN_UP) { composable(route = AppRoute.SIGN_UP) {
SignUpScreen(onNavigate = navController::navigate) SignUpScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.FORGOT_PASSWORD) { composable(route = AppRoute.FORGOT_PASSWORD) {
ForgotPasswordScreen(onNavigate = navController::navigate) ForgotPasswordScreen(onNavigate = navigateRoute)
} }
// Home // Home
composable(route = AppRoute.HOME) { composable(route = AppRoute.HOME) {
HomeScreen(onNavigate = navController::navigate) HomeScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.PARTNER_HOME) { composable(route = AppRoute.PARTNER_HOME) {
PartnerHomeScreen(onNavigate = navController::navigate) PartnerHomeScreen(onNavigate = navigateRoute)
} }
// Daily Question // Daily Question
composable(route = AppRoute.DAILY_QUESTION) { composable(route = AppRoute.DAILY_QUESTION) {
DailyQuestionScreen(onNavigate = navController::navigate) DailyQuestionScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.QUESTION_PACKS) { composable(route = AppRoute.QUESTION_PACKS) {
QuestionPackLibraryScreen(onNavigate = navController::navigate) QuestionPackLibraryScreen(onNavigate = navigateRoute)
} }
composable( composable(
route = AppRoute.QUESTION_CATEGORY, route = AppRoute.QUESTION_CATEGORY,
@ -123,11 +169,11 @@ fun AppNavigation(
) { ) {
QuestionCategoryScreen( QuestionCategoryScreen(
categoryId = it.arguments?.getString("categoryId") ?: "", categoryId = it.arguments?.getString("categoryId") ?: "",
onNavigate = navController::navigate onNavigate = navigateRoute
) )
} }
composable(route = AppRoute.QUESTION_COMPOSER) { composable(route = AppRoute.QUESTION_COMPOSER) {
QuestionComposerScreen(onNavigate = navController::navigate) QuestionComposerScreen(onNavigate = navigateRoute)
} }
// Question Thread // Question Thread
@ -153,7 +199,7 @@ fun AppNavigation(
questionId = it.arguments?.getString("questionId") ?: "", questionId = it.arguments?.getString("questionId") ?: "",
previousQuestionId = it.arguments?.getString("prevId"), previousQuestionId = it.arguments?.getString("prevId"),
nextQuestionId = it.arguments?.getString("nextId"), nextQuestionId = it.arguments?.getString("nextId"),
onNavigate = navController::navigate, onNavigate = navigateRoute,
onBack = { navController.popBackStack() } onBack = { navController.popBackStack() }
) )
} }
@ -165,25 +211,25 @@ fun AppNavigation(
) { ) {
AnswerRevealScreen( AnswerRevealScreen(
questionId = it.arguments?.getString("questionId") ?: "", questionId = it.arguments?.getString("questionId") ?: "",
onNavigate = navController::navigate onNavigate = navigateRoute
) )
} }
composable(route = AppRoute.ANSWER_HISTORY) { composable(route = AppRoute.ANSWER_HISTORY) {
AnswerHistoryScreen(onNavigate = navController::navigate) AnswerHistoryScreen(onNavigate = navigateRoute)
} }
// Pairing // Pairing
composable(route = AppRoute.CREATE_INVITE) { composable(route = AppRoute.CREATE_INVITE) {
CreateInviteScreen( CreateInviteScreen(
onNavigate = navController::navigate, onNavigate = navigateRoute,
onBack = { navController.popBackStack() } onBack = { navController.popBackStack() }
) )
} }
composable(route = AppRoute.EMAIL_INVITE) { composable(route = AppRoute.EMAIL_INVITE) {
EmailInviteScreen(onNavigate = navController::navigate) EmailInviteScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.ACCEPT_INVITE) { composable(route = AppRoute.ACCEPT_INVITE) {
AcceptInviteScreen(onNavigate = navController::navigate) AcceptInviteScreen(onNavigate = navigateRoute)
} }
composable( composable(
route = AppRoute.INVITE_CONFIRM, route = AppRoute.INVITE_CONFIRM,
@ -191,13 +237,13 @@ fun AppNavigation(
) { ) {
InviteConfirmScreen( InviteConfirmScreen(
inviteCode = it.arguments?.getString("inviteCode") ?: "", inviteCode = it.arguments?.getString("inviteCode") ?: "",
onNavigate = navController::navigate onNavigate = navigateRoute
) )
} }
// Wheel / Category Selection // Wheel / Category Selection
composable(route = AppRoute.CATEGORY_PICKER) { composable(route = AppRoute.CATEGORY_PICKER) {
CategoryPickerScreen(onNavigate = navController::navigate) CategoryPickerScreen(onNavigate = navigateRoute)
} }
composable( composable(
route = AppRoute.SPIN_WHEEL, route = AppRoute.SPIN_WHEEL,
@ -205,7 +251,7 @@ fun AppNavigation(
) { ) {
SpinWheelScreen( SpinWheelScreen(
categoryId = it.arguments?.getString("categoryId") ?: "", categoryId = it.arguments?.getString("categoryId") ?: "",
onNavigate = navController::navigate onNavigate = navigateRoute
) )
} }
composable( composable(
@ -214,7 +260,7 @@ fun AppNavigation(
) { ) {
WheelSessionScreen( WheelSessionScreen(
sessionId = it.arguments?.getString("sessionId") ?: "", sessionId = it.arguments?.getString("sessionId") ?: "",
onNavigate = navController::navigate onNavigate = navigateRoute
) )
} }
composable( composable(
@ -223,39 +269,39 @@ fun AppNavigation(
) { ) {
WheelCompleteScreen( WheelCompleteScreen(
sessionId = it.arguments?.getString("sessionId") ?: "", sessionId = it.arguments?.getString("sessionId") ?: "",
onNavigate = navController::navigate onNavigate = navigateRoute
) )
} }
composable(route = AppRoute.WHEEL_HISTORY) { composable(route = AppRoute.WHEEL_HISTORY) {
WheelHistoryScreen(onNavigate = navController::navigate) WheelHistoryScreen(onNavigate = navigateRoute)
} }
// Paywall // Paywall
composable(route = AppRoute.PAYWALL) { composable(route = AppRoute.PAYWALL) {
PaywallScreen(onNavigate = navController::navigate) PaywallScreen(onNavigate = navigateRoute)
} }
// Settings // Settings
composable(route = AppRoute.SETTINGS) { composable(route = AppRoute.SETTINGS) {
SettingsScreen(onNavigate = navController::navigate) SettingsScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.ACCOUNT) { composable(route = AppRoute.ACCOUNT) {
AccountScreen(onNavigate = navController::navigate) AccountScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.NOTIFICATIONS) { composable(route = AppRoute.NOTIFICATIONS) {
NotificationSettingsScreen(onNavigate = navController::navigate) NotificationSettingsScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.PRIVACY) { composable(route = AppRoute.PRIVACY) {
PrivacyScreen(onNavigate = navController::navigate) PrivacyScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.SUBSCRIPTION) { composable(route = AppRoute.SUBSCRIPTION) {
SubscriptionScreen(onNavigate = navController::navigate) SubscriptionScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.RELATIONSHIP_SETTINGS) { composable(route = AppRoute.RELATIONSHIP_SETTINGS) {
RelationshipSettingsScreen(onNavigate = navController::navigate) RelationshipSettingsScreen(onNavigate = navigateRoute)
} }
composable(route = AppRoute.DELETE_ACCOUNT) { composable(route = AppRoute.DELETE_ACCOUNT) {
DeleteAccountScreen(onNavigate = navController::navigate) DeleteAccountScreen(onNavigate = navigateRoute)
} }
} }
} }
@ -271,10 +317,25 @@ private val topLevelRoutes = listOf(
TopLevelRoute(AppRoute.HOME, "Home", Icons.Filled.Home), TopLevelRoute(AppRoute.HOME, "Home", Icons.Filled.Home),
TopLevelRoute(AppRoute.DAILY_QUESTION, "Today", Icons.Filled.Favorite), TopLevelRoute(AppRoute.DAILY_QUESTION, "Today", Icons.Filled.Favorite),
TopLevelRoute(AppRoute.QUESTION_PACKS, "Packs", Icons.Filled.Star), TopLevelRoute(AppRoute.QUESTION_PACKS, "Packs", Icons.Filled.Star),
TopLevelRoute(AppRoute.ANSWER_HISTORY, "Answers", Icons.Filled.Favorite), TopLevelRoute(AppRoute.ANSWER_HISTORY, "Answers", Icons.Filled.Done),
TopLevelRoute(AppRoute.SETTINGS, "Settings", Icons.Filled.Settings) TopLevelRoute(AppRoute.SETTINGS, "Settings", Icons.Filled.Settings)
) )
private val shellBackRoutes = setOf(
AppRoute.PARTNER_HOME,
AppRoute.QUESTION_CATEGORY,
AppRoute.QUESTION_COMPOSER,
AppRoute.QUESTION_THREAD,
AppRoute.ANSWER_REVEAL,
AppRoute.CATEGORY_PICKER,
AppRoute.SPIN_WHEEL,
AppRoute.WHEEL_SESSION,
AppRoute.WHEEL_COMPLETE,
AppRoute.ACCOUNT,
AppRoute.SUBSCRIPTION,
AppRoute.PAYWALL
)
@Composable @Composable
private fun AppBottomNavigation( private fun AppBottomNavigation(
currentRoute: String?, currentRoute: String?,

View File

@ -51,23 +51,23 @@ object AppRoute {
Definition(SIGN_UP, "Sign Up", "auth"), Definition(SIGN_UP, "Sign Up", "auth"),
Definition(FORGOT_PASSWORD, "Forgot Password", "auth"), Definition(FORGOT_PASSWORD, "Forgot Password", "auth"),
Definition(HOME, "Home", "home"), Definition(HOME, "Home", "home"),
Definition(PARTNER_HOME, "Partner Home", "home"), Definition(PARTNER_HOME, "Partner", "home"),
Definition(DAILY_QUESTION, "Daily Question", "questions"), Definition(DAILY_QUESTION, "Daily Question", "questions"),
Definition(QUESTION_PACKS, "Question Packs", "questions"), Definition(QUESTION_PACKS, "Question Packs", "questions"),
Definition(QUESTION_CATEGORY, "Question Category", "questions"), Definition(QUESTION_CATEGORY, "Question Pack", "questions"),
Definition(QUESTION_COMPOSER, "Question Composer", "questions"), Definition(QUESTION_COMPOSER, "New Question", "questions"),
Definition(QUESTION_THREAD, "Question Thread", "questions"), Definition(QUESTION_THREAD, "Answer", "questions"),
Definition(ANSWER_REVEAL, "Answer Reveal", "answers"), Definition(ANSWER_REVEAL, "Reveal", "answers"),
Definition(ANSWER_HISTORY, "Answer History", "answers"), Definition(ANSWER_HISTORY, "Answer History", "answers"),
Definition(CREATE_INVITE, "Create Invite", "pairing"), Definition(CREATE_INVITE, "Create Invite", "pairing"),
Definition(EMAIL_INVITE, "Email Invite", "pairing"), Definition(EMAIL_INVITE, "Email Invite", "pairing"),
Definition(ACCEPT_INVITE, "Accept Invite", "pairing"), Definition(ACCEPT_INVITE, "Accept Invite", "pairing"),
Definition(INVITE_CONFIRM, "Invite Confirm", "pairing"), Definition(INVITE_CONFIRM, "Invite Confirm", "pairing"),
Definition(CATEGORY_PICKER, "Category Picker", "wheel"), Definition(CATEGORY_PICKER, "Choose A Category", "wheel"),
Definition(SPIN_WHEEL, "Spin Wheel", "wheel"), Definition(SPIN_WHEEL, "Spin", "wheel"),
Definition(WHEEL_SESSION, "Wheel Session", "wheel"), Definition(WHEEL_SESSION, "Wheel Session", "wheel"),
Definition(WHEEL_COMPLETE, "Wheel Complete", "wheel"), Definition(WHEEL_COMPLETE, "Complete", "wheel"),
Definition(PAYWALL, "Paywall", "paywall"), Definition(PAYWALL, "Unlock Everything", "paywall"),
Definition(SETTINGS, "Settings", "settings"), Definition(SETTINGS, "Settings", "settings"),
Definition(ACCOUNT, "Account", "settings"), Definition(ACCOUNT, "Account", "settings"),
Definition(NOTIFICATIONS, "Notifications", "settings"), Definition(NOTIFICATIONS, "Notifications", "settings"),
@ -78,6 +78,52 @@ object AppRoute {
Definition(WHEEL_HISTORY, "Wheel History", "wheel") Definition(WHEEL_HISTORY, "Wheel History", "wheel")
) )
val topLevelRoutes = setOf(
HOME,
DAILY_QUESTION,
QUESTION_PACKS,
ANSWER_HISTORY,
SETTINGS
)
val onboardingAuthRoutes = setOf(
ONBOARDING,
CREATE_PROFILE,
LOGIN,
SIGN_UP,
FORGOT_PASSWORD
)
val modalLikeRoutes = setOf(
CREATE_INVITE,
EMAIL_INVITE,
ACCEPT_INVITE,
INVITE_CONFIRM,
PAYWALL
)
val drillInRoutes = setOf(
PARTNER_HOME,
QUESTION_CATEGORY,
QUESTION_COMPOSER,
QUESTION_THREAD,
ANSWER_REVEAL,
CATEGORY_PICKER,
SPIN_WHEEL,
WHEEL_SESSION,
WHEEL_COMPLETE,
WHEEL_HISTORY,
ACCOUNT,
NOTIFICATIONS,
PRIVACY,
SUBSCRIPTION,
RELATIONSHIP_SETTINGS,
DELETE_ACCOUNT
)
fun titleFor(route: String?): String? =
definitions.firstOrNull { it.route == route }?.title
fun answerReveal(questionId: String): String = "answer_reveal/${questionId.asRouteArg()}" fun answerReveal(questionId: String): String = "answer_reveal/${questionId.asRouteArg()}"
fun inviteConfirm(inviteCode: String): String = "invite_confirm/${inviteCode.asRouteArg()}" fun inviteConfirm(inviteCode: String): String = "invite_confirm/${inviteCode.asRouteArg()}"

View File

@ -106,7 +106,7 @@ private fun AnswerRevealContent(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(14.dp) horizontalArrangement = Arrangement.spacedBy(14.dp)
) { ) {
CircularProgressIndicator(color = Color(0xFFE07A5F)) CircularProgressIndicator(color = Color(0xFF8F5FC8))
Text("Loading reveal") Text("Loading reveal")
} }
} }
@ -166,7 +166,10 @@ private fun NoAnswerState(
onClick = onAnswerQuestion, onClick = onAnswerQuestion,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE07A5F)) colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) { ) {
Text("Answer") Text("Answer")
} }
@ -208,7 +211,10 @@ private fun ReadyToRevealState(
onClick = onReveal, onClick = onReveal,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE07A5F)) colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) { ) {
Text("Reveal") Text("Reveal")
} }
@ -247,7 +253,7 @@ private fun RevealedState(
Surface( Surface(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(20.dp), shape = RoundedCornerShape(20.dp),
color = Color(0xFFFFF5F1) color = Color(0xFFF8F0FF)
) { ) {
Text( Text(
text = answer.revealSummary(), text = answer.revealSummary(),

View File

@ -50,7 +50,10 @@ fun EmptyState(
onClick = onAction, onClick = onAction,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE07A5F)) colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) { ) {
Text(actionLabel) Text(actionLabel)
} }

View File

@ -37,7 +37,7 @@ fun LoadingState(
) { ) {
CircularProgressIndicator( CircularProgressIndicator(
modifier = Modifier.size(34.dp), modifier = Modifier.size(34.dp),
color = Color(0xFFE07A5F) color = Color(0xFF8F5FC8)
) )
Text( Text(
text = message, text = message,

View File

@ -54,7 +54,7 @@ fun PlaceholderScreen(
route: String, route: String,
onNavigate: (String) -> Unit, onNavigate: (String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
accent: Color = Color(0xFFE07A5F), accent: Color = Color(0xFFB98AF4),
primaryAction: PlaceholderAction? = null, primaryAction: PlaceholderAction? = null,
secondaryAction: PlaceholderAction? = null, secondaryAction: PlaceholderAction? = null,
chips: List<String> = emptyList(), chips: List<String> = emptyList(),
@ -128,7 +128,7 @@ fun PlaceholderScreen(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = accent, containerColor = accent,
contentColor = Color.White contentColor = Color(0xFF271236)
), ),
shape = RoundedCornerShape(16.dp) shape = RoundedCornerShape(16.dp)
) { ) {

View File

@ -24,31 +24,44 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
private val Purple = Color(0xFF7C6F9E) private val Purple = Color(0xFF5F3A87)
private val PurpleLight = Color(0xFFF0EDF9) private val PurpleLight = Color(0xFFF0EDF9)
private val GreenPill = Color(0xFF81B29A) private val GreenPill = Color(0xFF81B29A)
@Composable @Composable
fun SpecialDatesSection(modifier: Modifier = Modifier) { fun SpecialDatesSection(
modifier: Modifier = Modifier,
compact: Boolean = false
) {
Card( Card(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(28.dp), shape = RoundedCornerShape(if (compact) 24.dp else 28.dp),
colors = CardDefaults.cardColors(containerColor = Color.White), colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp) elevation = CardDefaults.cardElevation(defaultElevation = if (compact) 4.dp else 8.dp)
) { ) {
Column( Column(
modifier = Modifier.padding(20.dp), modifier = Modifier.padding(if (compact) 16.dp else 20.dp),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(if (compact) 12.dp else 16.dp)
) { ) {
Text( Row(
text = "Your Special Dates", modifier = Modifier.fillMaxWidth(),
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.SemiBold), horizontalArrangement = Arrangement.SpaceBetween,
color = Color(0xFF27211F) verticalAlignment = Alignment.CenterVertically
) ) {
Text(
text = "Your Special Dates",
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.SemiBold),
color = Color(0xFF27211F)
)
if (compact) {
DateCountPill()
}
}
// Anniversary featured card // Anniversary featured card
Surface( Surface(
@ -57,11 +70,11 @@ fun SpecialDatesSection(modifier: Modifier = Modifier) {
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Row( Row(
modifier = Modifier.padding(16.dp), modifier = Modifier.padding(if (compact) 13.dp else 16.dp),
horizontalArrangement = Arrangement.spacedBy(14.dp), horizontalArrangement = Arrangement.spacedBy(14.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
DateBlock(day = "14", month = "Jul", tint = Purple) DateBlock(day = "14", month = "Jul", tint = Purple, compact = compact)
Column( Column(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
@ -76,7 +89,9 @@ fun SpecialDatesSection(modifier: Modifier = Modifier) {
style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.SemiBold), style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.SemiBold),
color = Color(0xFF27211F) color = Color(0xFF27211F)
) )
TodayPill() if (!compact) {
TodayPill()
}
} }
Text( Text(
text = "Added by Jessica", text = "Added by Jessica",
@ -94,9 +109,19 @@ fun SpecialDatesSection(modifier: Modifier = Modifier) {
} }
} }
// Birthday rows if (compact) {
BirthdayRow(name = "Jessica", day = "10", month = "May") Text(
BirthdayRow(name = "Mark", day = "25", month = "Aug") text = "Next up: Jessica's birthday May 10, Mark's birthday Aug 25",
style = MaterialTheme.typography.bodySmall,
color = Color(0xFF4E4642),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
} else {
// Birthday rows
BirthdayRow(name = "Jessica", day = "10", month = "May")
BirthdayRow(name = "Mark", day = "25", month = "Aug")
}
} }
} }
} }
@ -174,6 +199,22 @@ private fun TodayPill() {
} }
} }
@Composable
private fun DateCountPill() {
Surface(
shape = RoundedCornerShape(999.dp),
color = PurpleLight
) {
Text(
text = "3 saved",
modifier = Modifier.padding(horizontal = 8.dp, vertical = 3.dp),
style = MaterialTheme.typography.labelSmall,
color = Purple,
fontWeight = FontWeight.SemiBold
)
}
}
@Preview(showBackground = true, backgroundColor = 0xFFFFFBFA) @Preview(showBackground = true, backgroundColor = 0xFFFFFBFA)
@Composable @Composable
fun SpecialDatesSectionPreview() { fun SpecialDatesSectionPreview() {

View File

@ -117,20 +117,18 @@ private fun HomeContent(
state.isLoading -> LoadingHomeCard() state.isLoading -> LoadingHomeCard()
state.error != null -> ErrorHomeCard(message = state.error, onRefresh = onRefresh) state.error != null -> ErrorHomeCard(message = state.error, onRefresh = onRefresh)
else -> { else -> {
DailyQuestionCard( TodayOverviewCard(
question = state.dailyQuestion, question = state.dailyQuestion,
stats = state.answerStats,
onDailyQuestion = onDailyQuestion, onDailyQuestion = onDailyQuestion,
onHistory = onHistory,
onPacks = onPacks onPacks = onPacks
) )
AnswerStatsRow( SpecialDatesSection(compact = true)
stats = state.answerStats,
onHistory = onHistory
)
LatestAnswerCard( LatestAnswerCard(
latest = state.answerStats.latest, latest = state.answerStats.latest,
onHistory = onHistory onHistory = onHistory
) )
SpecialDatesSection()
CategoryPreviewGrid( CategoryPreviewGrid(
categories = state.categories, categories = state.categories,
onCategory = onCategory, onCategory = onCategory,
@ -248,7 +246,7 @@ private fun PulsingInviteFab(
.size(56.dp) .size(56.dp)
.scale(ring1Scale) .scale(ring1Scale)
.background( .background(
color = Color(0xFFE07A5F).copy(alpha = ring1Alpha), color = Color(0xFFB98AF4).copy(alpha = ring1Alpha),
shape = CircleShape shape = CircleShape
) )
) )
@ -258,7 +256,7 @@ private fun PulsingInviteFab(
.size(56.dp) .size(56.dp)
.scale(ring2Scale) .scale(ring2Scale)
.background( .background(
color = Color(0xFFE07A5F).copy(alpha = ring2Alpha), color = Color(0xFFB98AF4).copy(alpha = ring2Alpha),
shape = CircleShape shape = CircleShape
) )
) )
@ -266,8 +264,8 @@ private fun PulsingInviteFab(
FloatingActionButton( FloatingActionButton(
onClick = onClick, onClick = onClick,
modifier = Modifier.size(56.dp).scale(fabScale), modifier = Modifier.size(56.dp).scale(fabScale),
containerColor = Color(0xFFE07A5F), containerColor = Color(0xFFB98AF4),
contentColor = Color.White, contentColor = Color(0xFF271236),
shape = CircleShape shape = CircleShape
) { ) {
Icon( Icon(
@ -279,6 +277,149 @@ private fun PulsingInviteFab(
} }
} }
@Composable
private fun TodayOverviewCard(
question: Question?,
stats: HomeAnswerStats,
onDailyQuestion: () -> Unit,
onHistory: () -> Unit,
onPacks: () -> Unit
) {
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(30.dp),
colors = CardDefaults.cardColors(containerColor = Color.White.copy(alpha = 0.9f)),
elevation = CardDefaults.cardElevation(defaultElevation = 14.dp)
) {
Column(
modifier = Modifier.padding(20.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
HomePill("Daily ritual")
question?.let { HomePill(it.category.displayCategoryName()) }
}
Text(
text = question?.text ?: "Your next question is ready.",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.SemiBold,
color = Color(0xFF27211F),
maxLines = 3,
overflow = TextOverflow.Ellipsis
)
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(22.dp),
color = Color(0xFFF8F0FF)
) {
Column(
modifier = Modifier.padding(14.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Next best action",
style = MaterialTheme.typography.labelLarge,
color = Color(0xFF6B4A86),
fontWeight = FontWeight.SemiBold
)
Text(
text = if (stats.private > 0) "${stats.private} private" else "${stats.total} saved",
style = MaterialTheme.typography.labelMedium,
color = Color(0xFF6B4A86)
)
}
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
OverviewMetric(
label = "Saved",
value = stats.total.toString(),
modifier = Modifier.weight(1f),
onClick = onHistory
)
OverviewMetric(
label = "Revealed",
value = stats.revealed.toString(),
modifier = Modifier.weight(1f),
onClick = onHistory
)
OverviewMetric(
label = "Private",
value = stats.private.toString(),
modifier = Modifier.weight(1f),
onClick = onHistory
)
}
}
}
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
Button(
onClick = onDailyQuestion,
modifier = Modifier.weight(1f),
shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) {
Text("Answer")
}
OutlinedButton(
onClick = onPacks,
modifier = Modifier.weight(1f),
shape = RoundedCornerShape(16.dp)
) {
Text("Packs")
}
}
}
}
}
@Composable
private fun OverviewMetric(
label: String,
value: String,
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
Card(
onClick = onClick,
modifier = modifier,
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color.White.copy(alpha = 0.72f)),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) {
Column(
modifier = Modifier.padding(horizontal = 12.dp, vertical = 10.dp),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
Text(
text = value,
style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.SemiBold),
color = Color(0xFF5F3A87),
maxLines = 1
)
Text(
text = label,
style = MaterialTheme.typography.labelMedium,
color = Color(0xFF4E4642),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}
@Composable @Composable
private fun DailyQuestionCard( private fun DailyQuestionCard(
question: Question?, question: Question?,
@ -314,7 +455,10 @@ private fun DailyQuestionCard(
onClick = onDailyQuestion, onClick = onDailyQuestion,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE07A5F)) colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) { ) {
Text("Open") Text("Open")
} }
@ -381,7 +525,7 @@ private fun StatCard(
Text( Text(
text = value, text = value,
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.SemiBold), style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.SemiBold),
color = Color(0xFFE07A5F) color = Color(0xFF5F3A87)
) )
Text( Text(
text = label, text = label,
@ -534,7 +678,7 @@ private fun LoadingHomeCard() {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(14.dp) horizontalArrangement = Arrangement.spacedBy(14.dp)
) { ) {
CircularProgressIndicator(color = Color(0xFFE07A5F)) CircularProgressIndicator(color = Color(0xFF8F5FC8))
Text( Text(
text = "Opening the local dashboard", text = "Opening the local dashboard",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
@ -572,7 +716,10 @@ private fun ErrorHomeCard(
Button( Button(
onClick = onRefresh, onClick = onRefresh,
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE07A5F)) colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) { ) {
Text("Retry") Text("Retry")
} }

View File

@ -55,7 +55,7 @@ fun PaywallScreen(
.fillMaxSize() .fillMaxSize()
.background( .background(
Brush.linearGradient( Brush.linearGradient(
listOf(Color(0xFFFFFBFA), Color(0xFFF5EEE8), Color(0xFFEAF0F4)), listOf(Color(0xFFFFFBFA), Color(0xFFF4ECFF), Color(0xFFEAF0F4)),
start = Offset.Zero, start = Offset.Zero,
end = Offset.Infinite end = Offset.Infinite
) )
@ -112,7 +112,7 @@ fun PaywallScreen(
Icon( Icon(
imageVector = Icons.Default.Check, imageVector = Icons.Default.Check,
contentDescription = null, contentDescription = null,
tint = Color(0xFFE07A5F), tint = Color(0xFF5F3A87),
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
Text( Text(
@ -128,7 +128,7 @@ fun PaywallScreen(
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(28.dp), shape = RoundedCornerShape(28.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFFE07A5F)), colors = CardDefaults.cardColors(containerColor = Color(0xFFB98AF4)),
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp) elevation = CardDefaults.cardElevation(defaultElevation = 6.dp)
) { ) {
Column( Column(
@ -139,12 +139,12 @@ fun PaywallScreen(
Text( Text(
text = "Coming soon", text = "Coming soon",
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = Color.White.copy(alpha = 0.8f) color = Color(0xFF271236).copy(alpha = 0.74f)
) )
Text( Text(
text = "In-app purchase launching with the next build.", text = "In-app purchase launching with the next build.",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = Color.White, color = Color(0xFF271236),
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
} }
@ -154,9 +154,12 @@ fun PaywallScreen(
onClick = { onNavigate("back") }, onClick = { onNavigate("back") },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE07A5F)) colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) { ) {
Text("Subscribe (coming soon)", color = Color.White) Text("Subscribe (coming soon)", color = Color(0xFF271236))
} }
TextButton(onClick = { onNavigate("back") }) { TextButton(onClick = { onNavigate("back") }) {

View File

@ -134,8 +134,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(0xFFE07A5F), containerColor = Color(0xFFB98AF4),
contentColor = Color.White contentColor = Color(0xFF271236)
) )
) { ) {
Text( Text(

View File

@ -197,7 +197,7 @@ private fun CategoryLoadingCard() {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(14.dp) horizontalArrangement = Arrangement.spacedBy(14.dp)
) { ) {
CircularProgressIndicator(color = Color(0xFFE07A5F)) CircularProgressIndicator(color = Color(0xFF8F5FC8))
Text( Text(
text = "Loading local prompts", text = "Loading local prompts",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,

View File

@ -129,8 +129,8 @@ 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(0xFFE07A5F), containerColor = Color(0xFFB98AF4),
contentColor = Color.White contentColor = Color(0xFF271236)
) )
) { ) {
Text("Unlock all packs") Text("Unlock all packs")
@ -236,7 +236,7 @@ private fun LoadingPackCard() {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(14.dp) horizontalArrangement = Arrangement.spacedBy(14.dp)
) { ) {
CircularProgressIndicator(color = Color(0xFFE07A5F)) CircularProgressIndicator(color = Color(0xFF8F5FC8))
Text( Text(
text = "Loading local packs", text = "Loading local packs",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,

View File

@ -209,7 +209,7 @@ private fun NotifToggleRow(
Switch( Switch(
checked = checked, checked = checked,
onCheckedChange = onCheckedChange, onCheckedChange = onCheckedChange,
colors = SwitchDefaults.colors(checkedThumbColor = Color(0xFFE07A5F), checkedTrackColor = Color(0xFFE07A5F).copy(alpha = 0.4f)) colors = SwitchDefaults.colors(checkedThumbColor = Color(0xFFB98AF4), checkedTrackColor = Color(0xFFB98AF4).copy(alpha = 0.4f))
) )
} }
} }

View File

@ -88,6 +88,12 @@ fun SettingsScreen(
) { ) {
// Profile card // Profile 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 = MaterialTheme.colorScheme.surfaceVariant)
@ -136,7 +142,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(0xFFE07A5F) else MaterialTheme.colorScheme.onSurfaceVariant tint = if (state.isPaired) Color(0xFF5F3A87) else MaterialTheme.colorScheme.onSurfaceVariant
) )
Column( Column(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
@ -162,16 +168,12 @@ fun SettingsScreen(
) )
} }
} }
if (!state.isPaired) { Icon(
Icon( Icons.AutoMirrored.Filled.ArrowForwardIos,
Icons.AutoMirrored.Filled.ArrowForwardIos, contentDescription = null,
contentDescription = null, modifier = Modifier.size(16.dp),
modifier = Modifier tint = MaterialTheme.colorScheme.primary
.size(16.dp) )
.clickable { onNavigate(AppRoute.CREATE_INVITE) },
tint = MaterialTheme.colorScheme.primary
)
}
} }
} }

View File

@ -17,7 +17,7 @@ fun SubscriptionScreen(
description = "A subscription management place for entitlement status, invoices, and plan changes.", description = "A subscription management place for entitlement status, invoices, and plan changes.",
route = AppRoute.SUBSCRIPTION, route = AppRoute.SUBSCRIPTION,
onNavigate = onNavigate, onNavigate = onNavigate,
accent = Color(0xFFE07A5F), accent = Color(0xFFB98AF4),
primaryAction = PlaceholderAction("Paywall", AppRoute.PAYWALL), primaryAction = PlaceholderAction("Paywall", AppRoute.PAYWALL),
secondaryAction = PlaceholderAction("Settings", AppRoute.SETTINGS), secondaryAction = PlaceholderAction("Settings", AppRoute.SETTINGS),
chips = listOf("Entitlement", "Plan", "Restore"), chips = listOf("Entitlement", "Plan", "Restore"),

View File

@ -3,8 +3,8 @@ package com.couplesconnect.app.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(0xFFE07A5F) val darkPrimaryColor = Color(0xFF8F5FC8)
val darkPrimaryContainerColor = Color(0xFF5C3828) val darkPrimaryContainerColor = Color(0xFF43255F)
val darkSecondaryColor = Color(0xFF81B29A) val darkSecondaryColor = Color(0xFF81B29A)
val darkTertiaryColor = Color(0xFFF2CC8F) val darkTertiaryColor = Color(0xFFF2CC8F)
val darkBackgroundColor = Color(0xFF1F1F1F) val darkBackgroundColor = Color(0xFF1F1F1F)
@ -12,6 +12,7 @@ val darkSurfaceColor = Color(0xFF2D2D2D)
val darkErrorColor = Color(0xFFE76F51) val darkErrorColor = Color(0xFFE76F51)
val darkOnPrimaryColor = Color(0xFFFFFFFF) val darkOnPrimaryColor = Color(0xFFFFFFFF)
val darkOnPrimaryContainerColor = Color(0xFFF3E8FF)
val darkOnSecondaryColor = Color(0xFFFFFFFF) val darkOnSecondaryColor = Color(0xFFFFFFFF)
val darkOnTertiaryColor = Color(0xFF3E3E3E) val darkOnTertiaryColor = Color(0xFF3E3E3E)
val darkOnBackgroundColor = Color(0xFFE0E0E0) val darkOnBackgroundColor = Color(0xFFE0E0E0)

View File

@ -21,9 +21,9 @@ fun CouplesConnectTheme(
) )
} }
// Warm color palette (Light theme) // Purple-pink color palette (Light theme)
val PrimaryColor = Color(0xFFE07A5F) val PrimaryColor = Color(0xFF8F5FC8)
val PrimaryContainerColor = Color(0xFFF5E6D3) val PrimaryContainerColor = Color(0xFFF3E8FF)
val SecondaryColor = Color(0xFF81B29A) val SecondaryColor = Color(0xFF81B29A)
val TertiaryColor = Color(0xFFF2CC8F) val TertiaryColor = Color(0xFFF2CC8F)
val BackgroundColor = Color(0xFFFFFBFA) val BackgroundColor = Color(0xFFFFFBFA)
@ -31,6 +31,7 @@ val SurfaceColor = Color(0xFFFFFBFA)
val ErrorColor = Color(0xFFE76F51) val ErrorColor = Color(0xFFE76F51)
val OnPrimaryColor = Color(0xFFFFFFFF) val OnPrimaryColor = Color(0xFFFFFFFF)
val OnPrimaryContainerColor = Color(0xFF321545)
val OnSecondaryColor = Color(0xFFFFFFFF) val OnSecondaryColor = Color(0xFFFFFFFF)
val OnTertiaryColor = Color(0xFF3E3E3E) val OnTertiaryColor = Color(0xFF3E3E3E)
val OnBackgroundColor = Color(0xFF3E3E3E) val OnBackgroundColor = Color(0xFF3E3E3E)
@ -41,6 +42,7 @@ val lightColors = lightColorScheme(
primary = PrimaryColor, primary = PrimaryColor,
onPrimary = OnPrimaryColor, onPrimary = OnPrimaryColor,
primaryContainer = PrimaryContainerColor, primaryContainer = PrimaryContainerColor,
onPrimaryContainer = OnPrimaryContainerColor,
secondary = SecondaryColor, secondary = SecondaryColor,
onSecondary = OnSecondaryColor, onSecondary = OnSecondaryColor,
tertiary = TertiaryColor, tertiary = TertiaryColor,
@ -57,6 +59,7 @@ val darkColors = darkColorScheme(
primary = PrimaryColor, primary = PrimaryColor,
onPrimary = OnPrimaryColor, onPrimary = OnPrimaryColor,
primaryContainer = PrimaryContainerColor, primaryContainer = PrimaryContainerColor,
onPrimaryContainer = OnPrimaryContainerColor,
secondary = SecondaryColor, secondary = SecondaryColor,
onSecondary = OnSecondaryColor, onSecondary = OnSecondaryColor,
tertiary = TertiaryColor, tertiary = TertiaryColor,

View File

@ -107,7 +107,7 @@ private fun CategoryPickerContent(
horizontalArrangement = Arrangement.spacedBy(14.dp), horizontalArrangement = Arrangement.spacedBy(14.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
CircularProgressIndicator(color = Color(0xFF7C6F9E)) CircularProgressIndicator(color = Color(0xFF5F3A87))
Text("Loading categories…", style = MaterialTheme.typography.bodyMedium, color = Color(0xFF4E4642)) Text("Loading categories…", style = MaterialTheme.typography.bodyMedium, color = Color(0xFF4E4642))
} }
} }

View File

@ -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(0xFF7C6F9E) color = if (state.spunAndReady) Color(0xFF81B29A) else Color(0xFF5F3A87)
) )
} }
} }
@ -173,7 +173,7 @@ private fun SpinWheelContent(
onClick = onStart, onClick = onStart,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(18.dp), shape = RoundedCornerShape(18.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF7C6F9E)) colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF5F3A87))
) { ) {
Text("Start session", color = Color.White) Text("Start session", color = Color.White)
} }
@ -185,7 +185,7 @@ private fun SpinWheelContent(
Text("Spin again") Text("Spin again")
} }
} }
state.isLoading -> CircularProgressIndicator(color = Color(0xFF7C6F9E)) state.isLoading -> CircularProgressIndicator(color = Color(0xFF5F3A87))
else -> { else -> {
Text( Text(
text = "Tap to select ${SpinWheelViewModel.SESSION_SIZE} questions at random", text = "Tap to select ${SpinWheelViewModel.SESSION_SIZE} questions at random",
@ -198,7 +198,7 @@ private fun SpinWheelContent(
onClick = onSpin, onClick = onSpin,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(18.dp), shape = RoundedCornerShape(18.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF7C6F9E)) colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF5F3A87))
) { ) {
Text("Spin", color = Color.White) Text("Spin", color = Color.White)
} }

View File

@ -203,9 +203,12 @@ private fun WheelHistoryLockedCard(onUnlock: () -> Unit) {
onClick = onUnlock, onClick = onUnlock,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE07A5F)) colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFB98AF4),
contentColor = Color(0xFF271236)
)
) { ) {
Text("Unlock premium", color = Color.White) Text("Unlock premium", color = Color(0xFF271236))
} }
} }
} }

View File

@ -120,7 +120,7 @@ private fun WheelSessionContent(
LinearProgressIndicator( LinearProgressIndicator(
progress = { progress }, progress = { progress },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
color = Color(0xFF7C6F9E), color = Color(0xFF5F3A87),
trackColor = Color(0xFFE8E4F0) trackColor = Color(0xFFE8E4F0)
) )
@ -158,7 +158,7 @@ private fun WheelSessionContent(
onClick = onNext, onClick = onNext,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(18.dp), shape = RoundedCornerShape(18.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF7C6F9E)) colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF5F3A87))
) { ) {
Text( Text(
text = if (current + 1 >= total) "Finish" else "Next question", text = if (current + 1 >= total) "Finish" else "Next question",