mirror of
https://github.com/tiennm99/loto.git
synced 2026-10-14 02:16:22 +00:00
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:
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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user