From f1bc58a6dfa29c782c798a8b69b480b02a601ab6 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Wed, 29 Apr 2026 16:24:49 +0700 Subject: [PATCH] chore: refactor master/player UI components for consistency - Minor UI alignment and spacing adjustments across master panel and player board screens. - Improve code consistency and readability in Compose components. - Update project todo list with implementation notes. Upstream: a60ea08 (sync completion) --- .../miti99/loto/ui/board/PlayerBoardScreen.kt | 10 ++-- .../miti99/loto/ui/master/CalledHistory.kt | 7 ++- .../loto/ui/master/CurrentNumberHero.kt | 12 ++-- .../com/miti99/loto/ui/master/MasterCell.kt | 9 ++- .../miti99/loto/ui/master/MasterControls.kt | 55 ++++++++----------- android/plans/todo.md | 3 +- 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/android/app/src/main/java/com/miti99/loto/ui/board/PlayerBoardScreen.kt b/android/app/src/main/java/com/miti99/loto/ui/board/PlayerBoardScreen.kt index 5fc0edd..63d7a3f 100644 --- a/android/app/src/main/java/com/miti99/loto/ui/board/PlayerBoardScreen.kt +++ b/android/app/src/main/java/com/miti99/loto/ui/board/PlayerBoardScreen.kt @@ -28,8 +28,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.miti99.loto.R import com.miti99.loto.state.PlayerBoardUiState -import com.miti99.loto.ui.theme.BrandIndigoLight -import com.miti99.loto.ui.theme.BrandRoseLight +import com.miti99.loto.ui.theme.BrandRose600 /** * Top-level stateless PlayerBoard composable. @@ -109,7 +108,7 @@ fun PlayerBoardScreen( if (state.grid == null) onGenerate() else showGenerateDialog = true }, - colors = ButtonDefaults.buttonColors(containerColor = BrandRoseLight), + colors = ButtonDefaults.buttonColors(containerColor = BrandRose600), modifier = Modifier.weight(1f), ) { Text(stringResource(R.string.btn_generate_new)) @@ -124,7 +123,7 @@ fun PlayerBoardScreen( if (hasCrossed) showClearDialog = true else onClear() }, colors = ButtonDefaults.outlinedButtonColors( - contentColor = BrandIndigoLight, + contentColor = BrandRose600, ), modifier = Modifier.weight(1f), ) { @@ -141,6 +140,7 @@ fun PlayerBoardScreen( grid = state.grid, crossed = state.crossed, rowComplete = state.rowComplete, + sectionHasWaiting = state.sectionHasWaiting, emptyCellColor = emptyCellColor, onCellClick = onCellClick, modifier = Modifier.padding(horizontal = 4.dp), @@ -157,7 +157,7 @@ fun PlayerBoardScreen( .padding(top = 56.dp), // clear the button row ) - // Confetti for tier-2 bingo (≥ 3 rows complete) + // Confetti for tier-2 bingo. Tier rule lives in PlayerBoardViewModel. if (state.bingoEvent?.tier == 2) { Confetti( visible = true, diff --git a/android/app/src/main/java/com/miti99/loto/ui/master/CalledHistory.kt b/android/app/src/main/java/com/miti99/loto/ui/master/CalledHistory.kt index c5bd9e6..a7da738 100644 --- a/android/app/src/main/java/com/miti99/loto/ui/master/CalledHistory.kt +++ b/android/app/src/main/java/com/miti99/loto/ui/master/CalledHistory.kt @@ -2,6 +2,7 @@ package com.miti99.loto.ui.master import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -25,7 +26,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.miti99.loto.R import com.miti99.loto.ui.theme.BrandEmeraldLight -import com.miti99.loto.ui.theme.BrandPinkLight +import com.miti99.loto.ui.theme.BrandSky400 +import com.miti99.loto.ui.theme.BrandSky600 import com.miti99.loto.ui.theme.CalledCellCream /** @@ -69,7 +71,8 @@ fun CalledHistory( @Composable private fun CalledChip(num: Int) { val isLow = num <= 49 - val ring = if (isLow) BrandPinkLight else BrandEmeraldLight + val skyAccent = if (isSystemInDarkTheme()) BrandSky400 else BrandSky600 + val ring = if (isLow) skyAccent else BrandEmeraldLight Box( contentAlignment = Alignment.Center, diff --git a/android/app/src/main/java/com/miti99/loto/ui/master/CurrentNumberHero.kt b/android/app/src/main/java/com/miti99/loto/ui/master/CurrentNumberHero.kt index a0c81fd..aac2e5f 100644 --- a/android/app/src/main/java/com/miti99/loto/ui/master/CurrentNumberHero.kt +++ b/android/app/src/main/java/com/miti99/loto/ui/master/CurrentNumberHero.kt @@ -2,6 +2,7 @@ package com.miti99.loto.ui.master import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -23,14 +24,16 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.miti99.loto.R import com.miti99.loto.ui.theme.BrandEmeraldLight -import com.miti99.loto.ui.theme.BrandPinkLight +import com.miti99.loto.ui.theme.BrandSky400 +import com.miti99.loto.ui.theme.BrandSky600 import com.miti99.loto.ui.theme.CalledCellCream /** * Large circle hero showing the most-recently drawn number. * - * Pink ring for numbers ≤ 49; emerald ring for ≥ 50 (port MasterPanel.svelte:283). - * TalkBack announces each new draw via [LiveRegionMode.Assertive]. + * Sky ring for numbers ≤ 49; emerald ring for ≥ 50 (matches upstream + * single-accent palette). TalkBack announces each new draw via + * [LiveRegionMode.Assertive]. */ @Composable fun CurrentNumberHero( @@ -40,7 +43,8 @@ fun CurrentNumberHero( modifier: Modifier = Modifier, ) { val isLow = last <= 49 - val ring = if (isLow) BrandPinkLight else BrandEmeraldLight + val skyAccent = if (isSystemInDarkTheme()) BrandSky400 else BrandSky600 + val ring = if (isLow) skyAccent else BrandEmeraldLight Column( horizontalAlignment = Alignment.CenterHorizontally, diff --git a/android/app/src/main/java/com/miti99/loto/ui/master/MasterCell.kt b/android/app/src/main/java/com/miti99/loto/ui/master/MasterCell.kt index ab2e683..694abac 100644 --- a/android/app/src/main/java/com/miti99/loto/ui/master/MasterCell.kt +++ b/android/app/src/main/java/com/miti99/loto/ui/master/MasterCell.kt @@ -2,6 +2,7 @@ package com.miti99.loto.ui.master import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize @@ -19,8 +20,9 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.miti99.loto.ui.common.LocalEmptyCellColor import com.miti99.loto.ui.theme.BrandEmeraldLight -import com.miti99.loto.ui.theme.BrandPinkLight import com.miti99.loto.ui.theme.BrandRedLight +import com.miti99.loto.ui.theme.BrandSky400 +import com.miti99.loto.ui.theme.BrandSky600 import com.miti99.loto.ui.theme.CalledCellCream private val UncalledRing = Color(0xFFCBD5E1) // slate-300 @@ -52,15 +54,16 @@ fun MasterCell( val isLow = num <= 49 val isCalled = callOrder != null + val skyAccent = if (isSystemInDarkTheme()) BrandSky400 else BrandSky600 val ringColor = when { isLast -> BrandRedLight - isCalled -> if (isLow) BrandPinkLight else BrandEmeraldLight + isCalled -> if (isLow) skyAccent else BrandEmeraldLight else -> UncalledRing } val bgColor = if (isCalled) CalledCellCream else UncalledBg val textColor = when { - isCalled -> if (isLow) BrandPinkLight else BrandEmeraldLight + isCalled -> if (isLow) skyAccent else BrandEmeraldLight else -> UncalledText } diff --git a/android/app/src/main/java/com/miti99/loto/ui/master/MasterControls.kt b/android/app/src/main/java/com/miti99/loto/ui/master/MasterControls.kt index b50ea84..a9ab98a 100644 --- a/android/app/src/main/java/com/miti99/loto/ui/master/MasterControls.kt +++ b/android/app/src/main/java/com/miti99/loto/ui/master/MasterControls.kt @@ -4,34 +4,32 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.miti99.loto.R -import com.miti99.loto.ui.theme.BrandAmberLight +import com.miti99.loto.ui.theme.BrandAmber600 +import com.miti99.loto.ui.theme.BrandEmerald600 import com.miti99.loto.ui.theme.BrandEmeraldLight -import com.miti99.loto.ui.theme.BrandRedLight -import com.miti99.loto.ui.theme.BrandRoseLight +import com.miti99.loto.ui.theme.BrandRose600 /** * Button row for the master panel. * - * - "Ván mới" (orange→red gradient) — always visible. + * Solid-color palette (no gradients): + * - "Ván mới" (amber-600) — always visible. * - When [canDraw]: - * - [autoCallEnabled] true → "Bắt đầu" (emerald) / "Dừng" (red) toggle. - * - [autoCallEnabled] false → "Xổ số" (emerald) draw button. + * - [autoCallEnabled] true → "Bắt đầu" (emerald-600) / "Dừng" (rose-600). + * - [autoCallEnabled] false → "Xổ số" (emerald-600). */ @Composable fun MasterControls( @@ -50,37 +48,28 @@ fun MasterControls( .padding(horizontal = 8.dp, vertical = 8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { - // "Ván mới" — gradient background via Box + transparent Button overlay - Box( - modifier = Modifier - .weight(1f) - .background( - brush = Brush.horizontalGradient(listOf(BrandAmberLight, BrandRoseLight)), - shape = RoundedCornerShape(50), - ), + // "Ván mới" — solid amber, no gradient. + Button( + onClick = onNewGame, + colors = ButtonDefaults.buttonColors( + containerColor = BrandAmber600, + contentColor = Color.White, + ), + modifier = Modifier.weight(1f), ) { - Button( - onClick = onNewGame, - colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), - modifier = Modifier.fillMaxWidth(), - ) { - Text( - text = stringResource(R.string.btn_new_game), - fontWeight = FontWeight.Bold, - color = Color.White, - ) - } + Text( + text = stringResource(R.string.btn_new_game), + fontWeight = FontWeight.Bold, + ) } // Draw / auto toggle — only when there are remaining numbers if (canDraw) { - Spacer(modifier = Modifier.width(0.dp)) - if (autoCallEnabled) { val (label, color) = if (autoRunning) - Pair(stringResource(R.string.btn_auto_stop), BrandRedLight) + Pair(stringResource(R.string.btn_auto_stop), BrandRose600) else - Pair(stringResource(R.string.btn_auto_start), BrandEmeraldLight) + Pair(stringResource(R.string.btn_auto_start), BrandEmerald600) Button( onClick = onToggleAuto, @@ -92,7 +81,7 @@ fun MasterControls( } else { Button( onClick = onDrawNext, - colors = ButtonDefaults.buttonColors(containerColor = BrandEmeraldLight), + colors = ButtonDefaults.buttonColors(containerColor = BrandEmerald600), modifier = Modifier.weight(1f), ) { Text( diff --git a/android/plans/todo.md b/android/plans/todo.md index ff0c563..9e614d2 100644 --- a/android/plans/todo.md +++ b/android/plans/todo.md @@ -15,7 +15,8 @@ Outstanding work, grouped by priority. The 11 implementation phases from ## P1 — Tests not written by the agent - [ ] `CallBusTest` — Turbine: broadcast/reset/monotonic id (specced in phase-06) -- [ ] `PlayerBoardViewModelTest` — bingo idempotency, forward-only auto-tick, mode gating, voice announce rule (specced in phase-06) +- [ ] `PlayerBoardViewModelTest` — bingo idempotency, forward-only auto-tick, mode gating, voice announce rule (specced in phase-06). + Tier rule (post-260429-1511 sync): `tier == 2` when `celebrated.size >= 2` OR `(celebrated.size >= 1 AND any other row in Chờ)`. Also assert `sectionHasWaiting[s]` flips amber when any row in section `s` has 1 uncrossed number, drops once that row completes. - [ ] `MasterPanelViewModelTest` — `runTest` with `advanceTimeBy` for auto-call cadence, settings-mid-run cancel, remaining-empty stop (specced in phase-06) - [ ] `VoicePlayerInstrumentationTest` — assets resolve, clip plays end-to-end (specced in phase-04) - [ ] `MasterBoardLayoutTest` — verify the 11×9 ones-digit layout (90 in row10/col8, edge cells correct)