fix(ui): remove hardcoded colors in BucketList, DateMatch, QuestionThread, WheelHistory; delete unused PlaceholderScreen
This commit is contained in:
parent
8b7bbc2996
commit
b10395812b
|
|
@ -1,358 +0,0 @@
|
|||
package app.closer.ui.components
|
||||
|
||||
import app.closer.ui.theme.closerBackgroundBrush
|
||||
import app.closer.ui.theme.closerSoftSurfaceColor
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.rotate
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
data class PlaceholderAction(
|
||||
val label: String,
|
||||
val route: String
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun PlaceholderScreen(
|
||||
title: String,
|
||||
section: String,
|
||||
description: String,
|
||||
route: String,
|
||||
onNavigate: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
accent: Color = Color(0xFFB98AF4),
|
||||
primaryAction: PlaceholderAction? = null,
|
||||
secondaryAction: PlaceholderAction? = null,
|
||||
chips: List<String> = emptyList(),
|
||||
details: List<String> = emptyList()
|
||||
) {
|
||||
val background = closerBackgroundBrush()
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(background)
|
||||
) {
|
||||
DepthBackdrop(accent = accent)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.safeDrawingPadding()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = 22.dp, vertical = 18.dp)
|
||||
.navigationBarsPadding(),
|
||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||
) {
|
||||
PlaceholderHeader(
|
||||
section = section,
|
||||
title = title,
|
||||
description = description,
|
||||
accent = accent
|
||||
)
|
||||
|
||||
if (chips.isNotEmpty()) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.horizontalScroll(rememberScrollState()),
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
chips.forEach { chip ->
|
||||
SignalChip(label = chip, accent = accent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PreviewPanel(
|
||||
title = "What belongs here",
|
||||
accent = accent,
|
||||
details = details.ifEmpty {
|
||||
listOf(
|
||||
"The main moment is easy to find",
|
||||
"Important choices have room to breathe",
|
||||
"The path forward stays clear"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
primaryAction?.let { action ->
|
||||
Button(
|
||||
onClick = { onNavigate(action.route) },
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = accent,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary
|
||||
),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = action.label,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
secondaryAction?.let { action ->
|
||||
OutlinedButton(
|
||||
onClick = { onNavigate(action.route) },
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
contentColor = MaterialTheme.colorScheme.onSurface
|
||||
),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = action.label,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PlaceholderHeader(
|
||||
section: String,
|
||||
title: String,
|
||||
description: String,
|
||||
accent: Color
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.statusBarsPadding(),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
SignalChip(label = section, accent = accent)
|
||||
Text(
|
||||
text = "Guided",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.54f),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.displaySmall.copy(
|
||||
fontWeight = FontWeight.SemiBold
|
||||
),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
Text(
|
||||
text = description,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 6,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SignalChip(
|
||||
label: String,
|
||||
accent: Color
|
||||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(999.dp),
|
||||
color = Color.White.copy(alpha = 0.72f),
|
||||
tonalElevation = 0.dp,
|
||||
shadowElevation = 0.dp,
|
||||
modifier = Modifier.border(
|
||||
width = 1.dp,
|
||||
brush = Brush.horizontalGradient(
|
||||
listOf(accent.copy(alpha = 0.42f), Color.White.copy(alpha = 0.2f))
|
||||
),
|
||||
shape = RoundedCornerShape(999.dp)
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = label,
|
||||
modifier = Modifier.padding(horizontal = 13.dp, vertical = 8.dp),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewPanel(
|
||||
title: String,
|
||||
accent: Color,
|
||||
details: List<String>
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(28.dp),
|
||||
color = Color.White.copy(alpha = 0.78f),
|
||||
tonalElevation = 0.dp,
|
||||
shadowElevation = 18.dp
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(18.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(14.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.background(accent.copy(alpha = 0.16f))
|
||||
.padding(horizontal = 10.dp, vertical = 6.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Ready",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = Color(0xFF56306F),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
details.take(4).forEachIndexed { index, detail ->
|
||||
DetailRow(
|
||||
detail = detail,
|
||||
accent = accent,
|
||||
index = index
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DetailRow(
|
||||
detail: String,
|
||||
accent: Color,
|
||||
index: Int
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(18.dp))
|
||||
.background(closerSoftSurfaceColor())
|
||||
.padding(14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(34.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(accent.copy(alpha = 0.16f)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = (index + 1).toString().padStart(2, '0'),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = Color(0xFF56306F),
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(
|
||||
text = detail,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.weight(1f),
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DepthBackdrop(accent: Color) {
|
||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||
rotate(degrees = -12f, pivot = Offset(size.width * 0.76f, size.height * 0.12f)) {
|
||||
drawRoundRect(
|
||||
brush = Brush.linearGradient(
|
||||
listOf(accent.copy(alpha = 0.26f), Color(0xFFE7A2D1).copy(alpha = 0.14f))
|
||||
),
|
||||
topLeft = Offset(size.width * 0.44f, -size.height * 0.05f),
|
||||
size = Size(size.width * 0.78f, size.height * 0.24f),
|
||||
cornerRadius = androidx.compose.ui.geometry.CornerRadius(72.dp.toPx())
|
||||
)
|
||||
}
|
||||
rotate(degrees = 9f, pivot = Offset(size.width * 0.18f, size.height * 0.78f)) {
|
||||
drawRoundRect(
|
||||
brush = Brush.linearGradient(
|
||||
listOf(Color(0xFFF4E8FF).copy(alpha = 0.32f), Color.White.copy(alpha = 0.08f))
|
||||
),
|
||||
topLeft = Offset(-size.width * 0.22f, size.height * 0.64f),
|
||||
size = Size(size.width * 0.74f, size.height * 0.22f),
|
||||
cornerRadius = androidx.compose.ui.geometry.CornerRadius(56.dp.toPx())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -248,7 +248,7 @@ private fun FilterChip(
|
|||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(999.dp),
|
||||
color = if (selected) Color(0xFFB98AF4) else Color(0xFFFFF8FC),
|
||||
color = if (selected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant,
|
||||
tonalElevation = if (selected) 0.dp else 2.dp,
|
||||
shadowElevation = if (selected) 0.dp else 2.dp,
|
||||
modifier = Modifier
|
||||
|
|
@ -378,13 +378,13 @@ private fun CategoryBadge(
|
|||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(999.dp),
|
||||
color = Color(0xFFF3E8FF)
|
||||
color = MaterialTheme.colorScheme.primaryContainer
|
||||
) {
|
||||
Text(
|
||||
text = category.replaceFirstChar { it.uppercase() },
|
||||
modifier = Modifier.padding(horizontal = 11.dp, vertical = 6.dp),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = Color(0xFF56306F),
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
}
|
||||
|
|
@ -406,7 +406,7 @@ private fun AddItemDialog(
|
|||
Surface(
|
||||
modifier = Modifier.padding(20.dp),
|
||||
shape = RoundedCornerShape(28.dp),
|
||||
color = Color.White
|
||||
color = MaterialTheme.colorScheme.surface
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -459,10 +459,10 @@ private fun AddItemDialog(
|
|||
modifier = Modifier.weight(1f),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0xFFE3D4EB)
|
||||
containerColor = MaterialTheme.colorScheme.secondaryContainer
|
||||
)
|
||||
) {
|
||||
Text("Cancel", color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
Text("Cancel", color = MaterialTheme.colorScheme.onSecondaryContainer)
|
||||
}
|
||||
|
||||
Button(
|
||||
|
|
@ -470,7 +470,7 @@ private fun AddItemDialog(
|
|||
modifier = Modifier.weight(1f),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0xFFB98AF4),
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary
|
||||
)
|
||||
) {
|
||||
|
|
@ -489,7 +489,7 @@ private fun CategoryChip(
|
|||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(999.dp),
|
||||
color = if (selected) Color(0xFFB98AF4) else Color(0xFFFFF8FC),
|
||||
color = if (selected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant,
|
||||
tonalElevation = if (selected) 0.dp else 2.dp,
|
||||
shadowElevation = if (selected) 0.dp else 2.dp,
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -239,18 +239,18 @@ private fun DateMatchHeader(
|
|||
IconButton(onClick = onViewMatches) {
|
||||
Surface(
|
||||
shape = CircleShape,
|
||||
color = Color(0xFFF3E8FF)
|
||||
color = MaterialTheme.colorScheme.primaryContainer
|
||||
) {
|
||||
Box(modifier = Modifier.padding(8.dp)) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Favorite,
|
||||
contentDescription = "View matches",
|
||||
tint = Color(0xFF56306F)
|
||||
tint = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
)
|
||||
if (matchCount > 0) {
|
||||
Surface(
|
||||
shape = CircleShape,
|
||||
color = Color(0xFF8D2D35),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
.align(Alignment.TopEnd)
|
||||
|
|
@ -258,7 +258,7 @@ private fun DateMatchHeader(
|
|||
Text(
|
||||
text = matchCount.toString(),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = Color.White,
|
||||
color = MaterialTheme.colorScheme.onError,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ private fun WaitingPhase(
|
|||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
color = Color.White.copy(alpha = 0.78f)
|
||||
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.78f)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(18.dp),
|
||||
|
|
|
|||
|
|
@ -355,13 +355,13 @@ private fun GameHistoryLockedCard(onUnlock: () -> Unit) {
|
|||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(50.dp),
|
||||
color = Color(0xFFF8F1FF)
|
||||
color = MaterialTheme.colorScheme.surfaceVariant
|
||||
) {
|
||||
Icon(
|
||||
Icons.Filled.Lock,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(16.dp).size(28.dp),
|
||||
tint = Color(0xFFB98AF4)
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
Text(
|
||||
|
|
|
|||
Loading…
Reference in New Issue