From 164c3ffce72f1f946266e9b58820bae1dbb1b0b9 Mon Sep 17 00:00:00 2001 From: Rene Luria Date: Fri, 28 Aug 2026 15:20:57 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20navigation=20par=20=C3=A9crans=20et=20a?= =?UTF-8?q?ccueil=20avec=20configuration=20de=20partie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/commonMain/kotlin/com/livrets/App.kt | 66 ++++++++++---- .../kotlin/com/livrets/ui/GameScreen.kt | 21 +++++ .../kotlin/com/livrets/ui/HistoryScreen.kt | 14 +++ .../kotlin/com/livrets/ui/HomeScreen.kt | 88 +++++++++++++++++++ .../kotlin/com/livrets/ui/ResultsScreen.kt | 14 +++ 5 files changed, 188 insertions(+), 15 deletions(-) create mode 100644 sharedUI/src/commonMain/kotlin/com/livrets/ui/GameScreen.kt create mode 100644 sharedUI/src/commonMain/kotlin/com/livrets/ui/HistoryScreen.kt create mode 100644 sharedUI/src/commonMain/kotlin/com/livrets/ui/HomeScreen.kt create mode 100644 sharedUI/src/commonMain/kotlin/com/livrets/ui/ResultsScreen.kt diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/App.kt b/sharedUI/src/commonMain/kotlin/com/livrets/App.kt index edad335..bcc8b16 100644 --- a/sharedUI/src/commonMain/kotlin/com/livrets/App.kt +++ b/sharedUI/src/commonMain/kotlin/com/livrets/App.kt @@ -1,27 +1,63 @@ package com.livrets -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import com.livrets.data.HistoryRepository +import com.livrets.game.GameConfig +import com.livrets.game.GameResult import com.livrets.theme.AppTheme +import com.livrets.ui.GameScreen +import com.livrets.ui.HistoryScreen +import com.livrets.ui.HomeScreen +import com.livrets.ui.ResultsScreen +import kotlinx.coroutines.launch +import okio.Path.Companion.toPath + +sealed interface Screen { + data object Home : Screen + data class Game(val config: GameConfig) : Screen + data class Results(val result: GameResult) : Screen + data object History : Screen +} @Composable fun App( filesDirPath: String, onThemeChanged: @Composable (isDark: Boolean) -> Unit = {}, ) = AppTheme(onThemeChanged) { - Box( - modifier = Modifier - .fillMaxSize() - .windowInsetsPadding(WindowInsets.safeDrawing), - contentAlignment = Alignment.Center, - ) { - Text("Livrets") + val scope = rememberCoroutineScope() + val history = remember { HistoryRepository("$filesDirPath/history.json".toPath()) } + var screen by remember { mutableStateOf(Screen.Home) } + + when (val current = screen) { + Screen.Home -> HomeScreen( + onPlay = { config -> screen = Screen.Game(config) }, + onHistory = { screen = Screen.History }, + ) + + is Screen.Game -> GameScreen( + config = current.config, + scope = scope, + onFinish = { result -> + screen = Screen.Results(result) + scope.launch { history.save(result) } + }, + onQuit = { screen = Screen.Home }, + ) + + is Screen.Results -> ResultsScreen( + result = current.result, + onReplay = { screen = Screen.Game(current.result.config) }, + onHome = { screen = Screen.Home }, + ) + + Screen.History -> HistoryScreen( + history = history, + onBack = { screen = Screen.Home }, + ) } } diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/ui/GameScreen.kt b/sharedUI/src/commonMain/kotlin/com/livrets/ui/GameScreen.kt new file mode 100644 index 0000000..70d3bb6 --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/ui/GameScreen.kt @@ -0,0 +1,21 @@ +package com.livrets.ui + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.livrets.game.GameConfig +import com.livrets.game.GameResult +import kotlinx.coroutines.CoroutineScope + +@Composable +fun GameScreen( + config: GameConfig, + scope: CoroutineScope, + onFinish: (GameResult) -> Unit, + onQuit: () -> Unit, +) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("Jeu") } +} diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/ui/HistoryScreen.kt b/sharedUI/src/commonMain/kotlin/com/livrets/ui/HistoryScreen.kt new file mode 100644 index 0000000..6d47275 --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/ui/HistoryScreen.kt @@ -0,0 +1,14 @@ +package com.livrets.ui + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.livrets.data.HistoryRepository + +@Composable +fun HistoryScreen(history: HistoryRepository, onBack: () -> Unit) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("Historique") } +} diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/ui/HomeScreen.kt b/sharedUI/src/commonMain/kotlin/com/livrets/ui/HomeScreen.kt new file mode 100644 index 0000000..d10090e --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/ui/HomeScreen.kt @@ -0,0 +1,88 @@ +package com.livrets.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.livrets.game.GameConfig + +@Composable +fun HomeScreen( + onPlay: (GameConfig) -> Unit, + onHistory: () -> Unit, +) { + var questionCount by remember { mutableStateOf(10) } + var secondsPerQuestion by remember { mutableStateOf(10) } + var maxTable by remember { mutableStateOf(12) } + + Column( + modifier = Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing) + .padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text("Livrets", style = MaterialTheme.typography.displayMedium) + Spacer(Modifier.height(32.dp)) + + StepperRow("Nombre de questions", questionCount, 5..50, step = 5) { questionCount = it } + StepperRow("Secondes par question", secondsPerQuestion, 3..30, step = 1) { secondsPerQuestion = it } + StepperRow("Jusqu'à la table de", maxTable, 1..12, step = 1) { maxTable = it } + + Spacer(Modifier.height(32.dp)) + Button( + onClick = { onPlay(GameConfig(questionCount, secondsPerQuestion, maxTable)) }, + modifier = Modifier.fillMaxWidth().height(56.dp), + ) { + Text("Jouer", fontSize = 20.sp) + } + TextButton(onClick = onHistory) { Text("Historique") } + } +} + +@Composable +private fun StepperRow( + label: String, + value: Int, + range: IntRange, + step: Int, + onChange: (Int) -> Unit, +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), + ) { + Text(label, modifier = Modifier.weight(1f)) + TextButton(onClick = { onChange((value - step).coerceAtLeast(range.first)) }) { Text("−") } + Text( + text = "$value", + modifier = Modifier.width(48.dp), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleMedium, + ) + TextButton(onClick = { onChange((value + step).coerceAtMost(range.last)) }) { Text("+") } + } +} diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/ui/ResultsScreen.kt b/sharedUI/src/commonMain/kotlin/com/livrets/ui/ResultsScreen.kt new file mode 100644 index 0000000..3c99282 --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/ui/ResultsScreen.kt @@ -0,0 +1,14 @@ +package com.livrets.ui + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.livrets.game.GameResult + +@Composable +fun ResultsScreen(result: GameResult, onReplay: () -> Unit, onHome: () -> Unit) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("Résultats") } +}