feat: implement table distribution logic and update UI for match assignments
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 43s

This commit is contained in:
Torsten Schulz (local)
2026-05-18 00:06:56 +02:00
parent 697e67d46e
commit 040e758044
4 changed files with 125 additions and 20 deletions

View File

@@ -94,6 +94,8 @@ internal fun TournamentEditorClassesTab(
var showAdd by remember { mutableStateOf(false) }
var newName by remember { mutableStateOf("") }
var newDoubles by remember { mutableStateOf(false) }
var showDistributedDialog by remember { mutableStateOf(false) }
var distributedMatches by remember { mutableStateOf<List<TournamentMatchDto>>(emptyList()) }
if (showAdd) {
AlertDialog(
onDismissRequest = { showAdd = false },
@@ -142,15 +144,56 @@ internal fun TournamentEditorClassesTab(
OutlinedButton(onClick = {
scope.launch {
runCatching {
withContext(Dispatchers.IO) {
val resp = withContext(Dispatchers.IO) {
api.distributeTables(de.tsschulz.tt_tagebuch.shared.api.models.TournamentClubTournamentBody(clubId, tournamentId))
}
// If server returned updated matches, fetch full match details to show names
if (resp.updated.isNotEmpty()) {
val allMatches = withContext(Dispatchers.IO) { api.listMatches(clubId, tournamentId) }
val ids = resp.updated.map { it.id }.toSet()
distributedMatches = allMatches.filter { it.id in ids }
showDistributedDialog = true
}
}.onFailure { onError(it.message) }
onReload()
}
}, modifier = Modifier.weight(1f)) {
Text(tr("tournaments.distributeTables", "Freie Tische verteilen"))
}
if (showDistributedDialog) {
AlertDialog(
onDismissRequest = { showDistributedDialog = false },
title = { Text(tr("tournaments.distributeTablesResult", "Tischverteilung")) },
text = {
Column(Modifier.fillMaxWidth()) {
// Header
Row(Modifier.fillMaxWidth().padding(bottom = 8.dp)) {
Text(tr("tournaments.playerA", "Spieler A"), modifier = Modifier.weight(1f), fontWeight = FontWeight.SemiBold)
Text(tr("tournaments.playerB", "Spieler B"), modifier = Modifier.weight(1f), fontWeight = FontWeight.SemiBold)
Text(tr("tournaments.tableShort", "Tisch"), modifier = Modifier.width(48.dp), fontWeight = FontWeight.SemiBold)
}
Divider()
LazyColumn {
items(distributedMatches) { m ->
val name1 = extractPlayerName(m.player1)
val name2 = extractPlayerName(m.player2)
Row(Modifier.fillMaxWidth().padding(vertical = 6.dp)) {
Text(name1, modifier = Modifier.weight(1f))
Text("", modifier = Modifier.width(16.dp), textAlign = androidx.compose.ui.text.style.TextAlign.Center)
Text(name2, modifier = Modifier.weight(1f))
Text((m.tableNumber ?: "-").toString(), modifier = Modifier.width(48.dp))
}
Divider()
}
}
}
},
confirmButton = {
TextButton(onClick = { showDistributedDialog = false }) { Text(tr("common.ok", "OK")) }
}
)
}
}
Column(verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = 12.dp)) {
classes.forEach { c ->
@@ -222,6 +265,30 @@ private fun ClassRowEditor(
}
}
private fun extractPlayerName(playerElem: JsonElement?): String {
try {
if (playerElem == null || playerElem is JsonNull) return "-"
val obj = playerElem.jsonObject
// Try member
val member = obj["member"]?.jsonObject
if (member != null) {
val first = member["firstName"]?.jsonPrimitive?.contentOrNull ?: ""
val last = member["lastName"]?.jsonPrimitive?.contentOrNull ?: ""
val name = "$first $last".trim()
if (name.isNotBlank()) return name
}
// Try direct fields
val first = obj["firstName"]?.jsonPrimitive?.contentOrNull
val last = obj["lastName"]?.jsonPrimitive?.contentOrNull
if (first != null || last != null) return listOfNotNull(first, last).joinToString(" ")
// Fallback to id
val id = obj["id"]?.jsonPrimitive?.intOrNull
return if (id != null) "#${id}" else "-"
} catch (e: Exception) {
return "-"
}
}
@Composable
internal fun TournamentEditorParticipantsTab(
clubId: Int,