feat(ui): layout adaptativo — portrait compacto en teléfonos
- Breakpoint 600dp: debajo, dashboard en una sola columna scrolleable (header, perfil+XP+llama compactos, semana, hábitos, mascota, equipo, museo); arriba, se mantiene el layout 3 columnas del PRD §5.2 - Onboarding: grid 2×2 en compacto, 4 columnas en tablet - Orientación desbloqueada en manifest (sensorLandscape fuera) - WeekRow extraído a componente compartido; TeamAccessCard y MuseumMiniCard ahora internal para reuso entre layouts
This commit is contained in:
@@ -20,10 +20,11 @@
|
||||
android:theme="@style/Theme.Rachita"
|
||||
tools:targetApi="34">
|
||||
|
||||
<!-- Orientation unlocked: tablets use the PRD landscape layout, phones get
|
||||
the compact portrait layout (width breakpoint in DashboardScreen). -->
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|smallestScreenSize|uiMode|density"
|
||||
android:theme="@style/Theme.Rachita">
|
||||
<intent-filter>
|
||||
|
||||
@@ -3,6 +3,7 @@ package mx.paputec.rachita.ui.dashboard
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
@@ -35,6 +36,7 @@ import mx.paputec.rachita.domain.model.BatteryStatus
|
||||
import mx.paputec.rachita.domain.model.HabitIcon
|
||||
import mx.paputec.rachita.domain.model.HabitPalette
|
||||
import mx.paputec.rachita.ui.dashboard.components.ConfettiOverlay
|
||||
import mx.paputec.rachita.ui.dashboard.components.DashboardCompact
|
||||
import mx.paputec.rachita.ui.dashboard.components.HabitCard
|
||||
import mx.paputec.rachita.ui.dashboard.components.RightColumn
|
||||
import mx.paputec.rachita.ui.dashboard.components.Sidebar
|
||||
@@ -47,6 +49,10 @@ import mx.paputec.rachita.ui.theme.SuccessGreen
|
||||
import mx.paputec.rachita.ui.theme.WarmGreyDeep
|
||||
|
||||
// Module 2 — dashboard root (PRD §5.2): sidebar 232 dp · center flex · right 296 dp.
|
||||
// Width breakpoint: below this the single-column phone layout is used; at or
|
||||
// above it, the PRD §5.2 three-column tablet layout.
|
||||
private val COMPACT_MAX_WIDTH = 600.dp
|
||||
|
||||
@Composable
|
||||
fun DashboardScreen(
|
||||
uiState: DashboardUiState,
|
||||
@@ -58,6 +64,31 @@ fun DashboardScreen(
|
||||
.background(CreamBackground)
|
||||
.padding(WindowInsets.safeDrawing.asPaddingValues()),
|
||||
) {
|
||||
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
|
||||
if (maxWidth < COMPACT_MAX_WIDTH) {
|
||||
DashboardCompact(
|
||||
uiState = uiState,
|
||||
onToggleHabit = onToggleHabit,
|
||||
header = { DashboardHeader(uiState = uiState) },
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
)
|
||||
} else {
|
||||
DashboardTablet(uiState = uiState, onToggleHabit = onToggleHabit)
|
||||
}
|
||||
}
|
||||
|
||||
// Confetti above everything (DA-04); confettiOn toggle arrives with Settings (DA-05).
|
||||
ConfettiOverlay(trigger = uiState.celebrationCount, enabled = true)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DashboardTablet(
|
||||
uiState: DashboardUiState,
|
||||
onToggleHabit: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -89,22 +120,14 @@ fun DashboardScreen(
|
||||
avatar = uiState.avatar,
|
||||
)
|
||||
}
|
||||
|
||||
// Confetti above everything (DA-04); confettiOn toggle arrives with Settings (DA-05).
|
||||
ConfettiOverlay(trigger = uiState.celebrationCount, enabled = true)
|
||||
}
|
||||
}
|
||||
|
||||
// Header shared by both layouts. Laid out as a plain top-anchored column with
|
||||
// height-bounded rows: on the EMUI test device a Bottom-aligned SpaceBetween
|
||||
// header measured ~270 dp tall (giant invisible text box), crushing the habit
|
||||
// list to zero height — see STATUS.md session 2.
|
||||
@Composable
|
||||
private fun CenterColumn(
|
||||
uiState: DashboardUiState,
|
||||
onToggleHabit: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
// Header laid out as a plain top-anchored column with height-bounded rows.
|
||||
// On the EMUI test device the previous Bottom-aligned SpaceBetween header
|
||||
// measured ~270 dp tall (giant invisible text box), crushing the habit list
|
||||
// to zero height — see STATUS.md session 2.
|
||||
private fun DashboardHeader(uiState: DashboardUiState, modifier: Modifier = Modifier) {
|
||||
val pendingText = when (uiState.pendingCount) {
|
||||
0 -> stringResource(R.string.dashboard_pending_zero)
|
||||
1 -> stringResource(R.string.dashboard_pending_one)
|
||||
@@ -131,6 +154,17 @@ private fun CenterColumn(
|
||||
uiState.battery?.let { BatteryChip(it) }
|
||||
TodayCounterPill(done = uiState.doneCount, total = uiState.totalCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CenterColumn(
|
||||
uiState: DashboardUiState,
|
||||
onToggleHabit: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
DashboardHeader(uiState = uiState)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
package mx.paputec.rachita.ui.dashboard.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import mx.paputec.rachita.R
|
||||
import mx.paputec.rachita.domain.model.AvatarKind
|
||||
import mx.paputec.rachita.domain.model.BatteryStatus
|
||||
import mx.paputec.rachita.domain.model.HabitIcon
|
||||
import mx.paputec.rachita.domain.model.HabitPalette
|
||||
import mx.paputec.rachita.ui.dashboard.DashboardUiState
|
||||
import mx.paputec.rachita.ui.dashboard.HabitCardUi
|
||||
import mx.paputec.rachita.ui.dashboard.WeekDayUi
|
||||
import mx.paputec.rachita.ui.onboarding.components.Mascot
|
||||
import mx.paputec.rachita.ui.theme.CoralIntense
|
||||
import mx.paputec.rachita.ui.theme.CreamCardSoft
|
||||
import mx.paputec.rachita.ui.theme.RachitaTheme
|
||||
import mx.paputec.rachita.ui.theme.SuccessGreen
|
||||
import mx.paputec.rachita.ui.theme.Sun
|
||||
import mx.paputec.rachita.ui.theme.WarmGreyDeep
|
||||
|
||||
// Phone-portrait dashboard: everything in one scrollable column, habits first
|
||||
// (the child's main job), profile/streak as compact strips. The tablet keeps
|
||||
// the PRD §5.2 three-column layout — see DashboardScreen.
|
||||
@Composable
|
||||
fun DashboardCompact(
|
||||
uiState: DashboardUiState,
|
||||
onToggleHabit: (String) -> Unit,
|
||||
header: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
item(key = "header") { header() }
|
||||
item(key = "profile") {
|
||||
CompactProfileStrip(
|
||||
avatar = uiState.avatar,
|
||||
childName = uiState.childName,
|
||||
level = uiState.level,
|
||||
xpInLevel = uiState.xpInLevel,
|
||||
xpTarget = uiState.xpTarget,
|
||||
streak = uiState.streak,
|
||||
)
|
||||
}
|
||||
item(key = "week") {
|
||||
CompactStreakStrip(week = uiState.week, securedToday = uiState.allDone)
|
||||
}
|
||||
items(count = uiState.habits.size, key = { uiState.habits[it].id }) { index ->
|
||||
val habit = uiState.habits[index]
|
||||
HabitCard(habit = habit, onToggle = { onToggleHabit(habit.id) })
|
||||
}
|
||||
item(key = "mascot") {
|
||||
MascotMessageCard(
|
||||
avatar = uiState.avatar,
|
||||
message = if (uiState.allDone) {
|
||||
stringResource(R.string.dashboard_mascot_celebrate, uiState.childName)
|
||||
} else {
|
||||
stringResource(R.string.dashboard_mascot_normal)
|
||||
},
|
||||
)
|
||||
}
|
||||
item(key = "team") { TeamAccessCard() }
|
||||
item(key = "museum") { MuseumMiniCard() }
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar essentials condensed into one card: mascot + name/level + XP bar +
|
||||
// streak flame with count.
|
||||
@Composable
|
||||
private fun CompactProfileStrip(
|
||||
avatar: AvatarKind,
|
||||
childName: String,
|
||||
level: Int,
|
||||
xpInLevel: Int,
|
||||
xpTarget: Int,
|
||||
streak: Int,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(Color.White)
|
||||
.padding(14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Mascot(kind = avatar, modifier = Modifier.size(64.dp))
|
||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(text = childName, style = MaterialTheme.typography.titleMedium)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(999.dp))
|
||||
.background(Sun.copy(alpha = 0.25f))
|
||||
.padding(horizontal = 8.dp, vertical = 2.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.dashboard_level_badge, level),
|
||||
style = MaterialTheme.typography.labelSmall.copy(color = CoralIntense),
|
||||
)
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(8.dp)
|
||||
.clip(RoundedCornerShape(999.dp))
|
||||
.background(CreamCardSoft),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(fraction = (xpInLevel.toFloat() / xpTarget).coerceIn(0f, 1f))
|
||||
.height(8.dp)
|
||||
.clip(RoundedCornerShape(999.dp))
|
||||
.background(Sun),
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.dashboard_xp_progress, xpInLevel, xpTarget),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
)
|
||||
}
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
StreakFlame(modifier = Modifier.size(28.dp, 34.dp))
|
||||
Text(
|
||||
text = streak.toString(),
|
||||
style = MaterialTheme.typography.titleLarge.copy(color = CoralIntense),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CompactStreakStrip(week: List<WeekDayUi>, securedToday: Boolean) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color.White)
|
||||
.padding(horizontal = 12.dp, vertical = 10.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
WeekRow(week = week)
|
||||
AnimatedVisibility(
|
||||
visible = securedToday,
|
||||
enter = slideInVertically { it / 2 } + fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(999.dp))
|
||||
.background(SuccessGreen.copy(alpha = 0.15f))
|
||||
.padding(horizontal = 14.dp, vertical = 6.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.dashboard_streak_secured),
|
||||
style = MaterialTheme.typography.labelMedium.copy(color = SuccessGreen),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFFFF6EE, widthDp = 412, heightDp = 915)
|
||||
@Composable
|
||||
private fun PreviewDashboardCompact() {
|
||||
RachitaTheme {
|
||||
DashboardCompact(
|
||||
uiState = DashboardUiState(
|
||||
childName = "Lucía",
|
||||
avatar = AvatarKind.Fox,
|
||||
habits = listOf(
|
||||
HabitCardUi("banarse", "Bañarse", "Antes de dormir", HabitIcon.Drop, HabitPalette.Mint, true),
|
||||
HabitCardUi("dormir", "Dormir temprano", "A las 9:00 pm", HabitIcon.Moon, HabitPalette.Lilac, false),
|
||||
HabitCardUi("escuela", "Ir a la escuela", "Sin faltar nunca", HabitIcon.School, HabitPalette.Coral, false),
|
||||
),
|
||||
streak = 12,
|
||||
week = listOf(
|
||||
WeekDayUi("L", true, false),
|
||||
WeekDayUi("M", true, false),
|
||||
WeekDayUi("M", true, false),
|
||||
WeekDayUi("J", false, true),
|
||||
WeekDayUi("V", false, false),
|
||||
WeekDayUi("S", false, false),
|
||||
WeekDayUi("D", false, false),
|
||||
),
|
||||
level = 7,
|
||||
xpInLevel = 320,
|
||||
battery = BatteryStatus(86, isCharging = false),
|
||||
dateLine = "Lunes 22 de junio",
|
||||
isLoading = false,
|
||||
),
|
||||
onToggleHabit = {},
|
||||
header = {
|
||||
Text(text = "¡Hola, Lucía!", style = MaterialTheme.typography.headlineMedium)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,9 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
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.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Check
|
||||
import androidx.compose.material.icons.rounded.Favorite
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -124,44 +122,8 @@ private fun StreakCard(streak: Int, week: List<WeekDayUi>, securedToday: Boolean
|
||||
}
|
||||
}
|
||||
|
||||
// DA-07: L M M J V S D circles, checked on secured days.
|
||||
@Composable
|
||||
private fun WeekRow(week: List<WeekDayUi>) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
) {
|
||||
week.forEach { day ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(30.dp)
|
||||
.clip(CircleShape)
|
||||
.background(if (day.secured) Coral else CreamCardSoft)
|
||||
.then(
|
||||
if (day.isToday) Modifier.border(2.dp, CoralIntense, CircleShape) else Modifier,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
if (day.secured) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Check,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(16.dp),
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = day.label,
|
||||
style = MaterialTheme.typography.labelSmall.copy(color = WarmGreyDeep),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TeamAccessCard() {
|
||||
internal fun TeamAccessCard() {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -198,7 +160,7 @@ fun MascotMessageCard(avatar: AvatarKind, message: String, modifier: Modifier =
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MuseumMiniCard() {
|
||||
internal fun MuseumMiniCard() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package mx.paputec.rachita.ui.dashboard.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Check
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import mx.paputec.rachita.ui.dashboard.WeekDayUi
|
||||
import mx.paputec.rachita.ui.theme.Coral
|
||||
import mx.paputec.rachita.ui.theme.CoralIntense
|
||||
import mx.paputec.rachita.ui.theme.CreamCardSoft
|
||||
import mx.paputec.rachita.ui.theme.RachitaTheme
|
||||
import mx.paputec.rachita.ui.theme.WarmGreyDeep
|
||||
|
||||
// DA-07: L M M J V S D circles with checks on secured days. Shared by the
|
||||
// tablet right column and the compact (portrait) streak strip.
|
||||
@Composable
|
||||
fun WeekRow(week: List<WeekDayUi>, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
) {
|
||||
week.forEach { day ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(30.dp)
|
||||
.clip(CircleShape)
|
||||
.background(if (day.secured) Coral else CreamCardSoft)
|
||||
.then(
|
||||
if (day.isToday) Modifier.border(2.dp, CoralIntense, CircleShape) else Modifier,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
if (day.secured) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Check,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(16.dp),
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = day.label,
|
||||
style = MaterialTheme.typography.labelSmall.copy(color = WarmGreyDeep),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFFFF6EE, widthDp = 320)
|
||||
@Composable
|
||||
private fun PreviewWeekRow() {
|
||||
RachitaTheme {
|
||||
WeekRow(
|
||||
week = listOf(
|
||||
WeekDayUi("L", true, false),
|
||||
WeekDayUi("M", true, false),
|
||||
WeekDayUi("M", false, false),
|
||||
WeekDayUi("J", false, false),
|
||||
WeekDayUi("V", false, true),
|
||||
WeekDayUi("S", false, false),
|
||||
WeekDayUi("D", false, false),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
@@ -76,26 +77,28 @@ fun OnboardingScreen(
|
||||
|
||||
val insets = WindowInsets.safeDrawing.asPaddingValues()
|
||||
|
||||
Box(
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(CreamBackground)
|
||||
.padding(insets),
|
||||
) {
|
||||
// 2×2 grid on phones/portrait, 4-across on the tablet target (PRD layout).
|
||||
val isCompact = maxWidth < 600.dp
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 32.dp, vertical = 24.dp),
|
||||
.padding(horizontal = if (isCompact) 20.dp else 32.dp, vertical = if (isCompact) 16.dp else 24.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
OnboardingHeader(childName = uiState.childName)
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(4),
|
||||
columns = GridCells.Fixed(if (isCompact) 2 else 4),
|
||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
||||
contentPadding = PaddingValues(vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(20.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(if (isCompact) 14.dp else 20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(if (isCompact) 14.dp else 20.dp),
|
||||
) {
|
||||
items(items = AvatarOptions, key = { it.kind }) { option ->
|
||||
AvatarCard(
|
||||
|
||||
Reference in New Issue
Block a user