One centred column for the main menu
The games moved a level down when the menus became a tree, so the top screen now holds three sections and two buttons. Spread across an adaptive grid that read as a page half empty rather than as a menu. One column, held in the middle, capped at 340dp so a tablet gets a menu rather than a row of very wide buttons. Join and Scorekeeper sit below the sections and run the same width, so the column stays a column all the way down rather than turning into a wrapped row at the top. The grid is still what the section screens use, where there are enough games for it to earn its place. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Urn6eEBA6XzrnfoibL7faC
This commit is contained in:
@@ -2,14 +2,15 @@ package org.prolibertate.games.ui
|
|||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
@@ -214,7 +215,7 @@ private fun AppContent(
|
|||||||
// Main menu
|
// Main menu
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainMenuScreen(
|
fun MainMenuScreen(
|
||||||
showComingSoon: Boolean,
|
showComingSoon: Boolean,
|
||||||
@@ -233,45 +234,52 @@ fun MainMenuScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { padding ->
|
) { padding ->
|
||||||
Column(
|
// Only the top of the tree. Trick-taking is reached through Card Games,
|
||||||
|
// which is where somebody looking for it would go.
|
||||||
|
val sections = GameMenu.entries.filter {
|
||||||
|
it.isTopLevel && GameCatalog.hasAnything(it, includeComingSoon = showComingSoon)
|
||||||
|
}
|
||||||
|
|
||||||
|
// One column, held in the middle. There are only ever a handful of
|
||||||
|
// entries here now that the games themselves live a level down, and a
|
||||||
|
// short list spread across a grid reads as a page half empty rather
|
||||||
|
// than as a menu. Capped in width so it does not become a row of very
|
||||||
|
// wide buttons on a tablet.
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(padding)
|
.padding(padding)
|
||||||
.padding(horizontal = 12.dp),
|
.padding(horizontal = 12.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
// Wraps rather than running off the edge: two buttons and a narrow
|
Column(
|
||||||
// phone would otherwise push the second one past the screen.
|
modifier = Modifier
|
||||||
FlowRow(
|
.widthIn(max = 340.dp)
|
||||||
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
|
.fillMaxWidth()
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
.verticalScroll(rememberScrollState()),
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
|
||||||
) {
|
|
||||||
OutlinedButton(onClick = onJoinGame) { Text("Join a game nearby") }
|
|
||||||
// Not a game, and deliberately not in the catalogue: it keeps
|
|
||||||
// score for whatever is being played on the actual table.
|
|
||||||
OutlinedButton(onClick = onScorekeeper) { Text("Scorekeeper") }
|
|
||||||
}
|
|
||||||
|
|
||||||
// The column count follows the available width, so a phone in
|
|
||||||
// portrait gets two and a tablet in landscape gets four or more.
|
|
||||||
LazyVerticalGrid(
|
|
||||||
columns = GridCells.Adaptive(minSize = 172.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
) {
|
) {
|
||||||
// Only the top of the tree. Trick-taking is reached through
|
sections.forEach { section ->
|
||||||
// Card Games, which is where somebody looking for it would go.
|
|
||||||
val sections = GameMenu.entries.filter {
|
|
||||||
it.isTopLevel && GameCatalog.hasAnything(it, includeComingSoon = showComingSoon)
|
|
||||||
}
|
|
||||||
items(sections) { section ->
|
|
||||||
SectionTile(
|
SectionTile(
|
||||||
menu = section,
|
menu = section,
|
||||||
count = countIn(section, showComingSoon),
|
count = countIn(section, showComingSoon),
|
||||||
onClick = { onPickSection(section) },
|
onClick = { onPickSection(section) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Below the games, and full width like them, so the column
|
||||||
|
// stays one column all the way down.
|
||||||
|
OutlinedButton(
|
||||||
|
onClick = onJoinGame,
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(top = 8.dp),
|
||||||
|
) { Text("Join a game nearby") }
|
||||||
|
// Not a game, and deliberately not in the catalogue: it keeps
|
||||||
|
// score for whatever is being played on the actual table.
|
||||||
|
OutlinedButton(
|
||||||
|
onClick = onScorekeeper,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) { Text("Scorekeeper") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user