feat: historique des parties et statistiques de réussite par table

This commit is contained in:
herel committed 2026-08-28 15:27:13 +02:00
1 parent e3075853bf
commit 9b46efb020
1 file changed
+126 -2
@@ -1,14 +1,138 @@
package com.livrets.ui package com.livrets.ui
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.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
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.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.livrets.data.HistoryRepository import com.livrets.data.HistoryRepository
import com.livrets.game.GameResult
import com.livrets.game.TableStats
import com.livrets.game.tableStats
import kotlin.time.Instant
@Composable @Composable
fun HistoryScreen(history: HistoryRepository, onBack: () -> Unit) { fun HistoryScreen(
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("Historique") } history: HistoryRepository,
onBack: () -> Unit,
) {
var tab by remember { mutableIntStateOf(0) }
var games by remember { mutableStateOf<List<GameResult>>(emptyList()) }
LaunchedEffect(Unit) { games = history.load() }
Column(
modifier = Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.safeDrawing)
.padding(24.dp),
) {
Row(verticalAlignment = Alignment.CenterVertically) {
TextButton(onClick = onBack) { Text("←") }
Text("Historique", style = MaterialTheme.typography.headlineSmall)
}
TabRow(selectedTabIndex = tab) {
Tab(selected = tab == 0, onClick = { tab = 0 }, text = { Text("Parties") })
Tab(selected = tab == 1, onClick = { tab = 1 }, text = { Text("Tables") })
}
when (tab) {
0 -> Box(Modifier.weight(1f)) { GamesTab(games) }
else -> Box(Modifier.weight(1f)) { TablesTab(games.tableStats()) }
}
}
}
private fun formatDate(date: Instant): String =
date.toString().take(16).replace('T', ' ')
@Composable
private fun GamesTab(games: List<GameResult>) {
if (games.isEmpty()) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("Aucune partie enregistrée")
}
return
}
LazyColumn {
items(games.asReversed()) { game ->
Column(Modifier.fillMaxWidth().padding(vertical = 8.dp)) {
Text(
text = "${game.correctCount} / ${game.records.size}",
style = MaterialTheme.typography.titleLarge,
)
Text(
text = formatDate(game.date),
style = MaterialTheme.typography.bodySmall,
)
Text(
text = "${game.config.questionCount} questions · ${game.config.secondsPerQuestion} s par question · jusqu'à la table de ${game.config.maxTable}",
style = MaterialTheme.typography.bodySmall,
)
HorizontalDivider(modifier = Modifier.padding(top = 8.dp))
}
}
}
}
@Composable
private fun TablesTab(stats: List<TableStats>) {
LazyColumn {
items(stats) { stat ->
Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = "Table de ${stat.table}",
modifier = Modifier.width(110.dp),
style = MaterialTheme.typography.bodyMedium,
)
if (stat.attempts == 0) {
LinearProgressIndicator(
progress = { 0f },
modifier = Modifier.weight(1f),
)
Text("—", modifier = Modifier.padding(start = 8.dp))
} else {
LinearProgressIndicator(
progress = { stat.successRate.toFloat() },
modifier = Modifier.weight(1f),
color = if (stat.successRate < 0.6) MaterialTheme.colorScheme.error
else MaterialTheme.colorScheme.primary,
)
Text(
text = "${(stat.successRate * 100).toInt()} %",
modifier = Modifier.padding(start = 8.dp),
)
}
}
}
}
} }