Add restart option

This commit is contained in:
Christian Basler
2025-04-29 06:00:34 +02:00
parent d02043bbdb
commit f8d7702fca
6 changed files with 65 additions and 11 deletions

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#FFFFFF"
android:pathData="M360,840L303,784L367,720L360,720Q243,720 161.5,638.5Q80,557 80,440Q80,323 161.5,241.5Q243,160 360,160L600,160Q717,160 798.5,241.5Q880,323 880,440Q880,557 798.5,638.5Q717,720 600,720L600,640Q683,640 741.5,581.5Q800,523 800,440Q800,357 741.5,298.5Q683,240 600,240L360,240Q277,240 218.5,298.5Q160,357 160,440Q160,523 218.5,582.5Q277,642 360,648L376,648L304,576L360,520L520,680L360,840Z"/>
</vector>

View File

@@ -32,6 +32,7 @@ import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ch.dissem.yaep.domain.Clue import ch.dissem.yaep.domain.Clue
import ch.dissem.yaep.domain.Game
import ch.dissem.yaep.domain.Grid import ch.dissem.yaep.domain.Grid
import ch.dissem.yaep.domain.HorizontalClue import ch.dissem.yaep.domain.HorizontalClue
import ch.dissem.yaep.domain.ItemClass import ch.dissem.yaep.domain.ItemClass
@@ -39,7 +40,6 @@ import ch.dissem.yaep.domain.NeighbourClue
import ch.dissem.yaep.domain.OrderClue import ch.dissem.yaep.domain.OrderClue
import ch.dissem.yaep.domain.SameColumnClue import ch.dissem.yaep.domain.SameColumnClue
import ch.dissem.yaep.domain.TripletClue import ch.dissem.yaep.domain.TripletClue
import ch.dissem.yaep.domain.generateGame
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import yaep.commonui.generated.resources.Res import yaep.commonui.generated.resources.Res
import yaep.commonui.generated.resources.neighbour import yaep.commonui.generated.resources.neighbour
@@ -59,10 +59,9 @@ class DisplayClue<C : Clue>(val clue: C) {
} }
@Composable @Composable
fun App(modifier: Modifier = Modifier) { fun App(modifier: Modifier = Modifier, game: Game, onNewGame: () -> Unit, resetCluesBeacon: Any = Any()) {
var game by remember { mutableStateOf(generateGame()) } val horizontalClues = remember(game, resetCluesBeacon) { game.horizontalClues.map { DisplayClue(it) } }
val horizontalClues = remember(game) { game.horizontalClues.map { DisplayClue(it) } } val verticalClues = remember(game, resetCluesBeacon) { game.verticalClues.map { DisplayClue(it) } }
val verticalClues = remember(game) { game.verticalClues.map { DisplayClue(it) } }
val timer = remember(game) { GameTimer() } val timer = remember(game) { GameTimer() }
val time by timer.elapsedTime.collectAsState("00:00") val time by timer.elapsedTime.collectAsState("00:00")
var isSolved by remember(game) { mutableStateOf(false) } var isSolved by remember(game) { mutableStateOf(false) }
@@ -104,9 +103,7 @@ fun App(modifier: Modifier = Modifier) {
Text(time, fontSize = TextUnit(4f, TextUnitType.Em)) Text(time, fontSize = TextUnit(4f, TextUnitType.Em))
} }
} }
EndOfGame(isSolved = isSolved, time = time) { EndOfGame(isSolved = isSolved, time = time, onRestart = onNewGame)
game = generateGame()
}
} }
} }

View File

@@ -1,3 +1,5 @@
package ch.dissem.yaep.ui.desktop
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -14,17 +16,25 @@ import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale import androidx.compose.ui.draw.scale
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPlacement import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.WindowScope import androidx.compose.ui.window.WindowScope
import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.WindowState
import ch.dissem.yaep.domain.Game
import ch.dissem.yaep.ui.common.theme.AppTheme import ch.dissem.yaep.ui.common.theme.AppTheme
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import yaep.commonui.generated.resources.action_restart
import yaep.commonui.generated.resources.app_name_full import yaep.commonui.generated.resources.app_name_full
import yaep.commonui.generated.resources.moon import yaep.commonui.generated.resources.moon
import yaep.commonui.generated.resources.restart
import yaep.commonui.generated.resources.sun import yaep.commonui.generated.resources.sun
import yaep.commonui.generated.resources.window_close import yaep.commonui.generated.resources.window_close
import yaep.commonui.generated.resources.window_maximize import yaep.commonui.generated.resources.window_maximize
@@ -58,8 +68,17 @@ fun AppBar(
useDarkMode: Boolean, useDarkMode: Boolean,
setDarkMode: (Boolean) -> Unit, setDarkMode: (Boolean) -> Unit,
onCloseRequest: () -> Unit, onCloseRequest: () -> Unit,
onRestart: () -> Unit,
windowState: WindowState, windowState: WindowState,
game: Game,
) { ) {
var gameSolved by remember { mutableStateOf(false) }
LaunchedEffect(game) {
game.onSolved {
gameSolved = true
}
}
TopAppBar( TopAppBar(
navigationIcon = { navigationIcon = {
Image( Image(
@@ -70,6 +89,16 @@ fun AppBar(
}, },
title = { Text(text = stringResource(CRes.string.app_name_full)) }, title = { Text(text = stringResource(CRes.string.app_name_full)) },
actions = { actions = {
IconButton(
onClick = onRestart
) {
Icon(
painter = painterResource(CRes.drawable.action_restart),
contentDescription = stringResource(CRes.string.restart),
modifier = Modifier.size(SwitchDefaults.IconSize),
)
}
Spacer(Modifier.width(8.dp))
Switch( Switch(
checked = useDarkMode, checked = useDarkMode,
onCheckedChange = setDarkMode, onCheckedChange = setDarkMode,
@@ -98,6 +127,7 @@ fun AppBar(
) )
} }
IconButton( IconButton(
enabled = !gameSolved,
onClick = { onClick = {
windowState.placement = windowState.placement =
if (windowState.placement == WindowPlacement.Maximized) if (windowState.placement == WindowPlacement.Maximized)

View File

@@ -14,8 +14,12 @@ import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPlacement import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.application import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState import androidx.compose.ui.window.rememberWindowState
import ch.dissem.yaep.domain.Game
import ch.dissem.yaep.domain.generateGame
import ch.dissem.yaep.ui.common.App import ch.dissem.yaep.ui.common.App
import ch.dissem.yaep.ui.common.theme.emojiFontFamily import ch.dissem.yaep.ui.common.theme.emojiFontFamily
import ch.dissem.yaep.ui.desktop.AppBar
import ch.dissem.yaep.ui.desktop.DesktopWindow
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import yaep.commonui.generated.resources.app_name import yaep.commonui.generated.resources.app_name
@@ -35,6 +39,7 @@ fun main() = application {
placement = WindowPlacement.Floating, placement = WindowPlacement.Floating,
size = DpSize(1200.dp, 800.dp) size = DpSize(1200.dp, 800.dp)
) )
var game by remember { mutableStateOf<Game>(generateGame()) }
Window( Window(
onCloseRequest = ::exitApplication, onCloseRequest = ::exitApplication,
@@ -44,6 +49,7 @@ fun main() = application {
icon = painterResource(DRes.drawable.ic_launcher) icon = painterResource(DRes.drawable.ic_launcher)
) { ) {
var useDarkMode by remember { mutableStateOf(true) } var useDarkMode by remember { mutableStateOf(true) }
var resetCluesBeacon by remember { mutableStateOf(Any()) }
DesktopWindow( DesktopWindow(
useDarkMode = useDarkMode, useDarkMode = useDarkMode,
topBar = { topBar = {
@@ -51,11 +57,21 @@ fun main() = application {
useDarkMode = useDarkMode, useDarkMode = useDarkMode,
setDarkMode = { useDarkMode = it }, setDarkMode = { useDarkMode = it },
onCloseRequest = ::exitApplication, onCloseRequest = ::exitApplication,
windowState = windowState onRestart = {
do while (game.grid.undo());
resetCluesBeacon = Any()
},
windowState = windowState,
game = game,
) )
} }
) { ) {
App(modifier = Modifier.padding(it)) App(
modifier = Modifier.padding(it),
game = game,
onNewGame = { game = generateGame() },
resetCluesBeacon = resetCluesBeacon
)
} }
} }
} }

View File

@@ -37,6 +37,7 @@ class Game(
} }
} }
} }
grid.snapshot()
} }
fun onStart(listener: () -> Unit) { fun onStart(listener: () -> Unit) {

View File

@@ -1,5 +1,5 @@
[versions] [versions]
agp = "8.9.0" agp = "8.9.2"
jdk = "21" jdk = "21"
android-compileSdk = "35" android-compileSdk = "35"
android-minSdk = "24" android-minSdk = "24"