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)
This commit is contained in:
tiennm99 committed 2026-04-29 16:24:49 +07:00
1 parent 60df1dd7d0
commit f1bc58a6df
6 files changed
+48 -48

No files matched your search

@@ -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,
@@ -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,
@@ -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,
@@ -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
}
@@ -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(
+2 -1
View File
@@ -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)