feat: navigation par écrans et accueil avec configuration de partie

This commit is contained in:
herel committed 2026-08-28 15:20:57 +02:00
1 parent f8f506ae92
commit 164c3ffce7
5 files changed
+188 -15

No files matched your search

@@ -1,27 +1,63 @@
package com.livrets 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.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier 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.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 @Composable
fun App( fun App(
filesDirPath: String, filesDirPath: String,
onThemeChanged: @Composable (isDark: Boolean) -> Unit = {}, onThemeChanged: @Composable (isDark: Boolean) -> Unit = {},
) = AppTheme(onThemeChanged) { ) = AppTheme(onThemeChanged) {
Box( val scope = rememberCoroutineScope()
modifier = Modifier val history = remember { HistoryRepository("$filesDirPath/history.json".toPath()) }
.fillMaxSize() var screen by remember { mutableStateOf<Screen>(Screen.Home) }
.windowInsetsPadding(WindowInsets.safeDrawing),
contentAlignment = Alignment.Center, when (val current = screen) {
) { Screen.Home -> HomeScreen(
Text("Livrets") 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 },
)
} }
} }
@@ -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") }
}
@@ -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") }
}
@@ -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("+") }
}
}
@@ -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") }
}