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:
+3
@@ -11,5 +11,8 @@ data class Funktionaer(
|
||||
val email: String? = null,
|
||||
val telefon: String? = null,
|
||||
val vereinsNummer: String? = null,
|
||||
val nation: String? = "AUT",
|
||||
val bundesland: String? = null,
|
||||
val qualifikation: String? = null,
|
||||
val istAktiv: Boolean = true
|
||||
)
|
||||
|
||||
+121
-64
@@ -1,15 +1,19 @@
|
||||
package at.mocode.frontend.features.funktionaer.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.Gavel
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import at.mocode.frontend.core.designsystem.components.*
|
||||
@@ -40,14 +44,21 @@ fun FunktionaerScreen(
|
||||
onRichterNummerChange = { viewModel.send(FunktionaerIntent.EditRichterNummer(it)) },
|
||||
onEmailChange = { viewModel.send(FunktionaerIntent.EditEmail(it)) },
|
||||
onTelefonChange = { viewModel.send(FunktionaerIntent.EditTelefon(it)) },
|
||||
onNationChange = { viewModel.send(FunktionaerIntent.EditNation(it)) },
|
||||
onBundeslandChange = { viewModel.send(FunktionaerIntent.EditBundesland(it)) },
|
||||
onQualifikationChange = { viewModel.send(FunktionaerIntent.EditQualifikation(it)) },
|
||||
onSave = { viewModel.send(FunktionaerIntent.Save) },
|
||||
onCancel = { viewModel.send(FunktionaerIntent.Cancel) }
|
||||
)
|
||||
} else if (state.selectedFunktionaer != null) {
|
||||
FunktionaerCard(
|
||||
funktionaer = state.selectedFunktionaer!!,
|
||||
onEdit = { viewModel.send(FunktionaerIntent.Select(state.selectedFunktionaer)) }
|
||||
)
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
FunktionaerCardPreview(funktionaer = state.selectedFunktionaer!!)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
FunktionaerCard(
|
||||
funktionaer = state.selectedFunktionaer!!,
|
||||
onEdit = { viewModel.send(FunktionaerIntent.Select(state.selectedFunktionaer)) }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
PlaceholderContent(
|
||||
title = "Kein Funktionär ausgewählt",
|
||||
@@ -123,61 +134,26 @@ fun FunktionaerCard(
|
||||
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.Gavel,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.width(16.dp))
|
||||
Column {
|
||||
Text(
|
||||
"${funktionaer.vorname} ${funktionaer.nachname}",
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
"Richter-Nr: ${funktionaer.richterNummer ?: "-"}",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MsStatusBadge(
|
||||
text = if (funktionaer.istAktiv) "Aktiv" else "Inaktiv",
|
||||
containerColor = (if (funktionaer.istAktiv) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error).copy(alpha = 0.1f),
|
||||
contentColor = if (funktionaer.istAktiv) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error
|
||||
)
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
FunktionaerDetailItem(label = "Richter-Nr.", value = funktionaer.richterNummer ?: "-", modifier = Modifier.weight(1f))
|
||||
FunktionaerDetailItem(label = "Rollen", value = funktionaer.rollen.joinToString(", "), modifier = Modifier.weight(1f))
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(24.dp))
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
|
||||
Spacer(Modifier.height(24.dp))
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
FunktionaerDetailItem(label = "Rollen", value = funktionaer.rollen.joinToString(", "), modifier = Modifier.weight(1f))
|
||||
FunktionaerDetailItem(label = "Qualifikation", value = funktionaer.richterQualifikation ?: "-", modifier = Modifier.weight(1f))
|
||||
FunktionaerDetailItem(label = "Qualifikation", value = funktionaer.qualifikation ?: "-", modifier = Modifier.weight(1f))
|
||||
FunktionaerDetailItem(label = "Sparte(n)", value = funktionaer.qualifiziertFuerSparten.joinToString(", ").ifBlank { "-" }, modifier = Modifier.weight(1f))
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
FunktionaerDetailItem(label = "Nation", value = funktionaer.nation ?: "-", modifier = Modifier.weight(1f))
|
||||
FunktionaerDetailItem(label = "Bundesland", value = funktionaer.bundesland ?: "-", modifier = Modifier.weight(1f))
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
@@ -199,6 +175,50 @@ fun FunktionaerCard(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FunktionaerCardPreview(funktionaer: Funktionaer) {
|
||||
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.Person, 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("${funktionaer.vorname} ${funktionaer.nachname}", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
|
||||
MsStatusBadge(
|
||||
text = if (funktionaer.istAktiv) "Aktiv" else "Inaktiv",
|
||||
containerColor = (if (funktionaer.istAktiv) Color(0xFF2E7D32) else Color.Gray).copy(alpha = 0.1f),
|
||||
contentColor = if (funktionaer.istAktiv) Color(0xFF2E7D32) else Color.Gray
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = buildString {
|
||||
append("Nr: ${funktionaer.richterNummer ?: "-"}")
|
||||
if (!funktionaer.nation.isNullOrBlank()) append(" | ${funktionaer.nation}")
|
||||
if (!funktionaer.bundesland.isNullOrBlank()) append(" (${funktionaer.bundesland})")
|
||||
},
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FunktionaerDetailItem(label: String, value: String, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier) {
|
||||
@@ -215,17 +235,26 @@ private fun FunktionaerEditorContent(
|
||||
onRichterNummerChange: (String) -> Unit,
|
||||
onEmailChange: (String) -> Unit,
|
||||
onTelefonChange: (String) -> Unit,
|
||||
onNationChange: (String) -> Unit,
|
||||
onBundeslandChange: (String) -> Unit,
|
||||
onQualifikationChange: (String) -> Unit,
|
||||
onSave: () -> Unit,
|
||||
onCancel: () -> Unit
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
|
||||
MsActionToolbar(
|
||||
title = "Funktionär Details",
|
||||
title = if (state.selectedFunktionaer == null) "Funktionär anlegen" else "Funktionär Details",
|
||||
onSave = onSave,
|
||||
onCancel = onCancel
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(24.dp))
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
// Preview in Editor
|
||||
if (state.selectedFunktionaer != null) {
|
||||
FunktionaerCardPreview(funktionaer = state.selectedFunktionaer)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
MsTextField(
|
||||
@@ -246,13 +275,41 @@ private fun FunktionaerEditorContent(
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
MsTextField(
|
||||
value = state.editRichterNummer,
|
||||
onValueChange = onRichterNummerChange,
|
||||
label = "Richter-Nummer",
|
||||
modifier = Modifier.width(300.dp),
|
||||
compact = true
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
MsTextField(
|
||||
value = state.editRichterNummer,
|
||||
onValueChange = onRichterNummerChange,
|
||||
label = "Richter-Nummer",
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
MsTextField(
|
||||
value = state.editQualifikation,
|
||||
onValueChange = onQualifikationChange,
|
||||
label = "Qualifikation",
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
MsTextField(
|
||||
value = state.editNation,
|
||||
onValueChange = onNationChange,
|
||||
label = "Nation",
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
MsTextField(
|
||||
value = state.editBundesland,
|
||||
onValueChange = onBundeslandChange,
|
||||
label = "Bundesland",
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
|
||||
+18
-3
@@ -1,8 +1,8 @@
|
||||
package at.mocode.frontend.features.funktionaer.presentation
|
||||
|
||||
import at.mocode.frontend.features.funktionaer.domain.Funktionaer
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.mocode.frontend.features.funktionaer.domain.Funktionaer
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -26,6 +26,9 @@ data class FunktionaerState(
|
||||
val editRichterNummer: String = "",
|
||||
val editEmail: String = "",
|
||||
val editTelefon: String = "",
|
||||
val editNation: String = "AUT",
|
||||
val editBundesland: String = "",
|
||||
val editQualifikation: String = "",
|
||||
val errorMessage: String? = null,
|
||||
)
|
||||
|
||||
@@ -40,6 +43,9 @@ sealed interface FunktionaerIntent {
|
||||
data class EditRichterNummer(val value: String) : FunktionaerIntent
|
||||
data class EditEmail(val value: String) : FunktionaerIntent
|
||||
data class EditTelefon(val value: String) : FunktionaerIntent
|
||||
data class EditNation(val value: String) : FunktionaerIntent
|
||||
data class EditBundesland(val value: String) : FunktionaerIntent
|
||||
data class EditQualifikation(val value: String) : FunktionaerIntent
|
||||
data object Save : FunktionaerIntent
|
||||
data object Cancel : FunktionaerIntent
|
||||
data object ClearError : FunktionaerIntent
|
||||
@@ -69,7 +75,10 @@ class FunktionaerViewModel(
|
||||
editNachname = intent.funktionaer?.nachname ?: "",
|
||||
editRichterNummer = intent.funktionaer?.richterNummer ?: "",
|
||||
editEmail = intent.funktionaer?.email ?: "",
|
||||
editTelefon = intent.funktionaer?.telefon ?: ""
|
||||
editTelefon = intent.funktionaer?.telefon ?: "",
|
||||
editNation = intent.funktionaer?.nation ?: "AUT",
|
||||
editBundesland = intent.funktionaer?.bundesland ?: "",
|
||||
editQualifikation = intent.funktionaer?.qualifikation ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -81,7 +90,10 @@ class FunktionaerViewModel(
|
||||
editNachname = "",
|
||||
editRichterNummer = "",
|
||||
editEmail = "",
|
||||
editTelefon = ""
|
||||
editTelefon = "",
|
||||
editNation = "AUT",
|
||||
editBundesland = "",
|
||||
editQualifikation = ""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -90,6 +102,9 @@ class FunktionaerViewModel(
|
||||
is FunktionaerIntent.EditRichterNummer -> reduce { it.copy(editRichterNummer = intent.value) }
|
||||
is FunktionaerIntent.EditEmail -> reduce { it.copy(editEmail = intent.value) }
|
||||
is FunktionaerIntent.EditTelefon -> reduce { it.copy(editTelefon = intent.value) }
|
||||
is FunktionaerIntent.EditNation -> reduce { it.copy(editNation = intent.value) }
|
||||
is FunktionaerIntent.EditBundesland -> reduce { it.copy(editBundesland = intent.value) }
|
||||
is FunktionaerIntent.EditQualifikation -> reduce { it.copy(editQualifikation = intent.value) }
|
||||
is FunktionaerIntent.Save -> reduce { it.copy(isEditing = false) }
|
||||
is FunktionaerIntent.Cancel -> reduce { it.copy(isEditing = false) }
|
||||
is FunktionaerIntent.ClearError -> reduce { it.copy(errorMessage = null) }
|
||||
|
||||
Reference in New Issue
Block a user