chore: erweitere Pferd-, Funktionär- und Reiter-Modelle um neue Felder, verbessere UI und Suche

Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-21 13:47:35 +02:00
parent 574f8c470c
commit 2662d4e82e
10 changed files with 399 additions and 196 deletions
@@ -8,6 +8,7 @@ import androidx.compose.ui.graphics.Color
data class Pferd(
val id: String,
val name: String,
val kopfNummer: String? = null,
val lebensnummer: String,
val geschlecht: Geschlecht = Geschlecht.WALLACH,
val farbe: String = "",
@@ -1,6 +1,8 @@
package at.mocode.frontend.features.pferde.presentation
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Pets
@@ -8,6 +10,7 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import at.mocode.frontend.core.designsystem.components.*
@@ -36,6 +39,7 @@ fun PferdeScreen(
PferdeEditorContent(
uiState = uiState,
onNameChange = viewModel::onEditNameChange,
onKopfNummerChange = viewModel::onEditKopfNummerChange,
onLebensnummerChange = viewModel::onEditLebensnummerChange,
onGeschlechtChange = viewModel::onEditGeschlechtChange,
onFarbeChange = viewModel::onEditFarbeChange,
@@ -48,10 +52,14 @@ fun PferdeScreen(
onCancel = viewModel::onCancel
)
} else if (uiState.selectedPferd != null) {
PferdCard(
pferd = uiState.selectedPferd,
onEdit = { viewModel.selectPferd(uiState.selectedPferd) }
)
Column(Modifier.fillMaxSize()) {
PferdCardPreview(pferd = uiState.selectedPferd)
Spacer(Modifier.height(16.dp))
PferdCard(
pferd = uiState.selectedPferd,
onEdit = { viewModel.selectPferd(uiState.selectedPferd) }
)
}
} else {
PlaceholderContent(
title = "Kein Pferd ausgewählt",
@@ -88,6 +96,11 @@ private fun PferdeListContent(
MsDataTable(
items = uiState.searchResults,
columns = listOf(
MsColumnDefinition(
title = "Kopf-Nr.",
width = 80.dp,
cellRenderer = { Text(it.kopfNummer ?: "-", style = MaterialTheme.typography.bodySmall) }
),
MsColumnDefinition(
title = "Name",
weight = 1f,
@@ -127,61 +140,12 @@ fun PferdCard(
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
modifier = Modifier.fillMaxWidth().wrapContentHeight(),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
)
modifier = Modifier.fillMaxWidth().wrapContentHeight()
) {
Column(modifier = Modifier.padding(24.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Surface(
modifier = Modifier.size(48.dp),
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
) {
Box(contentAlignment = Alignment.Center) {
Icon(
Icons.Default.Pets,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(24.dp)
)
}
}
Spacer(Modifier.width(16.dp))
Column {
Text(
pferd.name,
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.Bold
)
Text(
pferd.lebensnummer,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
MsStatusBadge(
text = pferd.status.label,
containerColor = pferd.status.color.copy(alpha = 0.1f),
contentColor = pferd.status.color
)
}
Spacer(Modifier.height(24.dp))
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
Spacer(Modifier.height(24.dp))
Row(modifier = Modifier.fillMaxWidth()) {
DetailItem(label = "ÖPS-Nr.", value = pferd.oepsNummer ?: "-", modifier = Modifier.weight(1f))
DetailItem(label = "FEI-ID", value = pferd.feiId ?: "-", modifier = Modifier.weight(1f))
DetailItem(label = "Kopf-Nummer", value = pferd.kopfNummer ?: "-", modifier = Modifier.weight(1f))
DetailItem(label = "Lebensnummer", value = pferd.lebensnummer, modifier = Modifier.weight(1f))
}
Spacer(Modifier.height(16.dp))
@@ -195,15 +159,62 @@ fun PferdCard(
Row(modifier = Modifier.fillMaxWidth()) {
DetailItem(label = "Geburtsjahr", value = pferd.geburtsjahr?.toString() ?: "-", modifier = Modifier.weight(1f))
DetailItem(label = "ÖPS-Nr.", value = pferd.oepsNummer ?: "-", modifier = Modifier.weight(1f))
}
Spacer(Modifier.height(16.dp))
Row(modifier = Modifier.fillMaxWidth()) {
DetailItem(label = "FEI-ID", value = pferd.feiId ?: "-", modifier = Modifier.weight(1f))
DetailItem(label = "Besitzer", value = pferd.besitzer ?: "-", modifier = Modifier.weight(1f))
}
Spacer(Modifier.height(32.dp))
MsButton(
onClick = onEdit,
text = "Pferdedaten bearbeiten",
modifier = Modifier.fillMaxWidth()
onClick = onEdit,
fullWidth = true
)
}
}
}
}
@Composable
fun PferdCardPreview(pferd: Pferd) {
Card(
modifier = Modifier.fillMaxWidth().padding(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
) {
Row(
modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
Box(
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)),
contentAlignment = Alignment.Center
) {
Icon(Icons.Default.Pets, null, modifier = Modifier.size(32.dp), tint = MaterialTheme.colorScheme.primary)
}
Column(modifier = Modifier.weight(1f)) {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Text(pferd.name, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
MsStatusBadge(
text = pferd.status.label,
containerColor = pferd.status.color.copy(alpha = 0.1f),
contentColor = pferd.status.color
)
}
Text(
text = "Kopf-Nr: ${pferd.kopfNummer ?: "-"} | Lebensnummer: ${pferd.lebensnummer}",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -222,6 +233,7 @@ private fun DetailItem(label: String, value: String, modifier: Modifier = Modifi
private fun PferdeEditorContent(
uiState: PferdeUiState,
onNameChange: (String) -> Unit,
onKopfNummerChange: (String) -> Unit,
onLebensnummerChange: (String) -> Unit,
onGeschlechtChange: (Geschlecht) -> Unit,
onFarbeChange: (String) -> Unit,
@@ -233,23 +245,41 @@ private fun PferdeEditorContent(
onSave: () -> Unit,
onCancel: () -> Unit
) {
Column(modifier = Modifier.fillMaxSize()) {
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
MsActionToolbar(
title = "Pferde Details",
title = if (uiState.selectedPferd == null) "Pferd anlegen" else "Pferde Details",
onSave = onSave,
onCancel = onCancel
)
Spacer(Modifier.height(24.dp))
Spacer(Modifier.height(16.dp))
// Preview in Editor
if (uiState.selectedPferd != null) {
PferdCardPreview(pferd = uiState.selectedPferd)
Spacer(Modifier.height(16.dp))
}
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsTextField(
value = uiState.editName,
onValueChange = onNameChange,
label = "Name",
label = "Pferdename",
modifier = Modifier.weight(1.5f),
compact = true
)
MsTextField(
value = uiState.editKopfNummer,
onValueChange = onKopfNummerChange,
label = "Kopf-Nummer",
modifier = Modifier.weight(1f),
compact = true
)
}
Spacer(Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsTextField(
value = uiState.editLebensnummer,
onValueChange = onLebensnummerChange,
@@ -257,6 +287,13 @@ private fun PferdeEditorContent(
modifier = Modifier.weight(1f),
compact = true
)
MsTextField(
value = uiState.editOepsNummer,
onValueChange = onOepsNummerChange,
label = "ÖPS Nummer",
modifier = Modifier.weight(1f),
compact = true
)
}
Spacer(Modifier.height(16.dp))
@@ -26,7 +26,8 @@ data class PferdeUiState(
val editStatus: PferdeStatus = PferdeStatus.AKTIV,
val editFeiId: String = "",
val editOepsNummer: String = "",
val editBesitzer: String = ""
val editBesitzer: String = "",
val editKopfNummer: String = ""
)
/**
@@ -44,16 +45,33 @@ open class PferdeViewModel(initialLoad: Boolean = true) : ViewModel() {
private fun loadPferde() {
val mockData = listOf(
Pferd("1", "Bella", "040001234567801", Geschlecht.STUTE, "Braun", 2015, PferdeStatus.AKTIV),
Pferd("2", "Casanova", "040001234567802", Geschlecht.WALLACH, "Schimmel", 2012, PferdeStatus.AKTIV),
Pferd("3", "Spirit", "040001234567803", Geschlecht.HENGST, "Rappe", 2018, PferdeStatus.AKTIV),
Pferd("4", "Lucky", "040001234567804", Geschlecht.WALLACH, "Fuchs", 2010, PferdeStatus.VERKAUFT)
Pferd("1", "Bella", "1A23", "040001234567801", Geschlecht.STUTE, "Braun", 2015, PferdeStatus.AKTIV),
Pferd("2", "Casanova", "2B45", "040001234567802", Geschlecht.WALLACH, "Schimmel", 2012, PferdeStatus.AKTIV),
Pferd("3", "Spirit", "3C67", "040001234567803", Geschlecht.HENGST, "Rappe", 2018, PferdeStatus.AKTIV),
Pferd("4", "Lucky", "4D89", "040001234567804", Geschlecht.WALLACH, "Fuchs", 2010, PferdeStatus.VERKAUFT)
)
uiState = uiState.copy(searchResults = mockData)
}
fun onSearchQueryChange(query: String) {
uiState = uiState.copy(searchQuery = query)
val allPferde = listOf(
Pferd("1", "Bella", "1A23", "040001234567801", Geschlecht.STUTE, "Braun", 2015, PferdeStatus.AKTIV),
Pferd("2", "Casanova", "2B45", "040001234567802", Geschlecht.WALLACH, "Schimmel", 2012, PferdeStatus.AKTIV),
Pferd("3", "Spirit", "3C67", "040001234567803", Geschlecht.HENGST, "Rappe", 2018, PferdeStatus.AKTIV),
Pferd("4", "Lucky", "4D89", "040001234567804", Geschlecht.WALLACH, "Fuchs", 2010, PferdeStatus.VERKAUFT)
)
val filtered = if (query.isBlank()) {
allPferde
} else {
allPferde.filter {
it.name.contains(query, ignoreCase = true) ||
it.lebensnummer.contains(query, ignoreCase = true) ||
(it.kopfNummer?.contains(query, ignoreCase = true) ?: false)
}
}
uiState = uiState.copy(searchResults = filtered)
}
fun selectPferd(pferd: Pferd) {
@@ -69,7 +87,8 @@ open class PferdeViewModel(initialLoad: Boolean = true) : ViewModel() {
editStatus = pferd.status,
editFeiId = pferd.feiId ?: "",
editOepsNummer = pferd.oepsNummer ?: "",
editBesitzer = pferd.besitzer ?: ""
editBesitzer = pferd.besitzer ?: "",
editKopfNummer = pferd.kopfNummer ?: ""
)
}
@@ -86,7 +105,8 @@ open class PferdeViewModel(initialLoad: Boolean = true) : ViewModel() {
editStatus = PferdeStatus.AKTIV,
editFeiId = "",
editOepsNummer = "",
editBesitzer = ""
editBesitzer = "",
editKopfNummer = ""
)
}
@@ -102,6 +122,10 @@ open class PferdeViewModel(initialLoad: Boolean = true) : ViewModel() {
uiState = uiState.copy(editBesitzer = value)
}
fun onEditKopfNummerChange(value: String) {
uiState = uiState.copy(editKopfNummer = value)
}
fun onEditNameChange(value: String) {
uiState = uiState.copy(editName = value)
}