feat(pferde-feature): introduce Pferde management module with screens, ViewModel, and domain models

- Added `pferde-feature` module for managing horses, including list, detail, and editing views.
- Implemented `MsMasterDetailLayout` for PferdeScreen, integrating `MsDataTable`, `MsFilterBar`, and `MsActionToolbar`.
- Defined domain models (`Pferd`, `Geschlecht`, `PferdeStatus`) with mock data support.
- Updated roadmap to mark `Pferde-Verwaltung (MVP)` as complete.
- Registered the new module in `settings.gradle.kts` and `meldestelle-desktop` build configuration.
- Added previews for Pferde and Reiter components to support IDE render.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-03-31 12:19:54 +02:00
parent 94306329c9
commit 6bbf6dc966
13 changed files with 481 additions and 18 deletions
@@ -136,7 +136,7 @@ private fun ReiterEditorContent(
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsEnumDropdown(
label = "Lizenzklasse",
options = LizenzKlasse.values(),
options = LizenzKlasse.entries.toTypedArray(),
selectedOption = uiState.editLizenz,
onOptionSelected = onLizenzChange,
optionLabel = { it.label },
@@ -144,7 +144,7 @@ private fun ReiterEditorContent(
)
MsEnumDropdown(
label = "Hauptsparte",
options = Sparte.values(),
options = Sparte.entries.toTypedArray(),
selectedOption = uiState.editSparte,
onOptionSelected = onSparteChange,
optionLabel = { it.label },
@@ -167,3 +167,14 @@ private fun ReiterEditorContent(
}
}
}
@Composable
fun ReiterScreenPreviewContent() {
val viewModel = ReiterViewModel().apply {
// Optional: Hier könnten Mock-Daten direkt gesetzt werden,
// falls das ViewModel dies unterstützt.
}
MaterialTheme {
ReiterScreen(viewModel = viewModel)
}
}
@@ -28,13 +28,15 @@ data class ReiterUiState(
* ViewModel für die Reiter-Verwaltung.
* In einem echten Szenario würden wir hier ein Repository injizieren.
*/
class ReiterViewModel {
open class ReiterViewModel(initialLoad: Boolean = true) {
var uiState by mutableStateOf(ReiterUiState())
private set
protected set
init {
// Initialer Load (Mock-Daten)
loadReiter()
if (initialLoad) {
// Initialer Load (Mock-Daten)
loadReiter()
}
}
private fun loadReiter() {
@@ -0,0 +1,66 @@
package at.mocode.frontend.features.reiter.presentation
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import at.mocode.frontend.features.reiter.domain.LizenzKlasse
import at.mocode.frontend.features.reiter.domain.Reiter
import at.mocode.frontend.features.reiter.domain.ReiterStatus
import at.mocode.frontend.features.reiter.domain.Sparte
import at.mocode.wui.preview.ComponentPreview
/**
* Hilf's-ViewModel für die Vorschau, um den Status direkt setzen zu können.
*/
private class PreviewReiterViewModel(initialState: ReiterUiState) : ReiterViewModel(initialLoad = false) {
init {
uiState = initialState
}
}
@ComponentPreview
@Composable
fun PreviewReiterScreen_List() {
val viewModel = ReiterViewModel() // Nutzt die Mock-Daten aus dem init-Block
MaterialTheme {
ReiterScreen(viewModel = viewModel)
}
}
@ComponentPreview
@Composable
fun PreviewReiterScreen_Editing() {
val mockReiter = Reiter(
id = "1",
vorname = "Stefan",
nachname = "Möbius",
satznummer = "123456",
lizenz = LizenzKlasse.R2D2,
sparte = Sparte.DRESSUR,
status = ReiterStatus.AKTIV
)
val viewModel = PreviewReiterViewModel(
ReiterUiState(
searchResults = listOf(mockReiter),
selectedReiter = mockReiter,
isEditing = true,
editVorname = mockReiter.vorname,
editName = mockReiter.nachname,
editLizenz = mockReiter.lizenz,
editSparte = mockReiter.sparte,
editStatus = mockReiter.status
)
)
MaterialTheme {
ReiterScreen(viewModel = viewModel)
}
}
@ComponentPreview
@Composable
fun PreviewReiterScreen_Empty() {
val viewModel = PreviewReiterViewModel(ReiterUiState())
MaterialTheme {
ReiterScreen(viewModel = viewModel)
}
}