Hide unfinished games from production builds
A release listed all eleven games with nine of them marked "Coming soon", so most of the menu was a dead end for anyone installing from the production channel. Production now lists only what can be played; dev builds still show everything, which is where seeing the roadmap is useful. The menu reads the installed APK's own version name, so this follows the build rather than the update channel selected for the future — a dev build shows the full list even if its owner has switched back to production for updates. CatalogTest pins both views, including that filtering never empties a category and strands its heading. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN
This commit is contained in:
@@ -154,6 +154,22 @@ object GameCatalog {
|
||||
|
||||
fun byId(id: String): GameDescriptor? = all.firstOrNull { it.id == id }
|
||||
|
||||
fun byCategory(category: GameCategory): List<GameDescriptor> =
|
||||
all.filter { it.category == category }
|
||||
/**
|
||||
* Games in a category.
|
||||
*
|
||||
* [includeComingSoon] is what separates the two update channels: a dev
|
||||
* build lists everything, including the games that are still only entries
|
||||
* in this table, so the roadmap is visible while working on it. A
|
||||
* production build lists only what can actually be played, so nobody
|
||||
* downloads a release and taps into a dead end.
|
||||
*/
|
||||
fun byCategory(
|
||||
category: GameCategory,
|
||||
includeComingSoon: Boolean = true,
|
||||
): List<GameDescriptor> = all.filter {
|
||||
it.category == category && (includeComingSoon || it.available)
|
||||
}
|
||||
|
||||
/** Everything currently playable, regardless of category. */
|
||||
val playable: List<GameDescriptor> get() = all.filter { it.available }
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.prolibertate.games.game.engine.TableConfig
|
||||
import org.prolibertate.games.net.LobbyController
|
||||
import org.prolibertate.games.settings.Settings
|
||||
import org.prolibertate.games.settings.SettingsRepository
|
||||
import org.prolibertate.games.update.UpdateChannel
|
||||
import org.prolibertate.games.update.Updater
|
||||
|
||||
/** Everything the screens need, assembled once by the activity. */
|
||||
@@ -75,6 +76,12 @@ fun AppRoot(env: AppEnv) {
|
||||
val settings by env.settingsRepository.settings.collectAsState(initial = Settings())
|
||||
var stack by remember { mutableStateOf(listOf<Route>(Route.Menu)) }
|
||||
|
||||
// Read from the installed APK's own version name, so this follows the build
|
||||
// rather than the channel the user has selected for future updates.
|
||||
val showComingSoon = remember {
|
||||
env.updater.installedChannel() == UpdateChannel.DEV
|
||||
}
|
||||
|
||||
fun push(route: Route) {
|
||||
stack = stack + route
|
||||
}
|
||||
@@ -94,6 +101,9 @@ fun AppRoot(env: AppEnv) {
|
||||
|
||||
when (val route = stack.last()) {
|
||||
is Route.Menu -> MainMenuScreen(
|
||||
// Dev builds show the games that are not finished yet; production
|
||||
// releases list only what can actually be played.
|
||||
showComingSoon = showComingSoon,
|
||||
onPickGame = { push(Route.Setup(it.id)) },
|
||||
onJoinGame = { push(Route.Lobby(gameId = "", optionsJson = "{}", hosting = false)) },
|
||||
onSettings = { push(Route.Settings) },
|
||||
@@ -141,6 +151,7 @@ fun AppRoot(env: AppEnv) {
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MainMenuScreen(
|
||||
showComingSoon: Boolean,
|
||||
onPickGame: (GameDescriptor) -> Unit,
|
||||
onJoinGame: () -> Unit,
|
||||
onSettings: () -> Unit,
|
||||
@@ -175,6 +186,10 @@ fun MainMenuScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
GameCategory.entries.forEach { category ->
|
||||
val games = GameCatalog.byCategory(category, includeComingSoon = showComingSoon)
|
||||
// Don't leave a heading stranded over nothing.
|
||||
if (games.isEmpty()) return@forEach
|
||||
|
||||
item(span = { androidx.compose.foundation.lazy.grid.GridItemSpan(maxLineSpan) }) {
|
||||
Text(
|
||||
text = category.label,
|
||||
@@ -183,7 +198,7 @@ fun MainMenuScreen(
|
||||
modifier = Modifier.padding(top = 12.dp, bottom = 4.dp),
|
||||
)
|
||||
}
|
||||
items(GameCatalog.byCategory(category)) { game ->
|
||||
items(games) { game ->
|
||||
GameTile(game = game, onClick = { onPickGame(game) })
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user