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:
parent
94306329c9
commit
6bbf6dc966
|
|
@ -62,7 +62,7 @@ Hier bringen wir alles zusammen, bevor das finale Routing implementiert wird.
|
||||||
In dieser Phase werden die Komponenten zu echten Features zusammengebaut.
|
In dieser Phase werden die Komponenten zu echten Features zusammengebaut.
|
||||||
|
|
||||||
* [x] **Reiter-Verwaltung (MVP):** Erster Screen mit `MsMasterDetailLayout`, `MsDataTable` und Editor.
|
* [x] **Reiter-Verwaltung (MVP):** Erster Screen mit `MsMasterDetailLayout`, `MsDataTable` und Editor.
|
||||||
* [ ] **Pferde-Verwaltung (MVP):** Analog zur Reiter-Verwaltung.
|
* [x] **Pferde-Verwaltung (MVP):** Analog zur Reiter-Verwaltung (Fertiggestellt).
|
||||||
* [ ] **Navigation & Routing:** Integration der neuen Screens in die Hauptnavigation.
|
* [ ] **Navigation & Routing:** Integration der neuen Screens in die Hauptnavigation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
BIN
docs/ScreenShots/preview-idea-vorschau_2026-03-31_11-48.png
Normal file
BIN
docs/ScreenShots/preview-idea-vorschau_2026-03-31_11-48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 230 KiB |
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -40,3 +41,17 @@ fun MsCard(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Preview für IDE (muss in jvmMain liegen um in IDEA gerendert zu werden,
|
||||||
|
// oder hier bleiben als Dokumentation)
|
||||||
|
@Composable
|
||||||
|
fun MsCardPreviewContent() {
|
||||||
|
MaterialTheme {
|
||||||
|
Column(modifier = Modifier.padding(16.dp)) {
|
||||||
|
MsCard {
|
||||||
|
Text("Dies ist eine MsCard", style = MaterialTheme.typography.bodyMedium)
|
||||||
|
Text("Mit High-Density Content.", style = MaterialTheme.typography.bodySmall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
32
frontend/features/pferde-feature/build.gradle.kts
Normal file
32
frontend/features/pferde-feature/build.gradle.kts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Feature-Modul: Pferde-Verwaltung (Desktop-only)
|
||||||
|
*/
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
|
alias(libs.plugins.composeMultiplatform)
|
||||||
|
alias(libs.plugins.composeCompiler)
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "at.mocode.clients"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
sourceSets {
|
||||||
|
jvmMain.dependencies {
|
||||||
|
implementation(projects.frontend.core.designSystem)
|
||||||
|
implementation(projects.frontend.core.domain)
|
||||||
|
implementation(projects.frontend.core.navigation)
|
||||||
|
implementation(compose.desktop.currentOs)
|
||||||
|
implementation(compose.foundation)
|
||||||
|
implementation(compose.runtime)
|
||||||
|
implementation(compose.material3)
|
||||||
|
implementation(compose.ui)
|
||||||
|
implementation(compose.materialIconsExtended)
|
||||||
|
implementation(libs.bundles.kmp.common)
|
||||||
|
implementation(libs.koin.core)
|
||||||
|
implementation(libs.koin.compose)
|
||||||
|
implementation(libs.koin.compose.viewmodel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package at.mocode.frontend.features.pferde.domain
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI-Modell für ein Pferd.
|
||||||
|
*/
|
||||||
|
data class Pferd(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val lebensnummer: String,
|
||||||
|
val geschlecht: Geschlecht = Geschlecht.WALLACH,
|
||||||
|
val farbe: String = "",
|
||||||
|
val geburtsjahr: Int? = null,
|
||||||
|
val status: PferdeStatus = PferdeStatus.AKTIV
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class Geschlecht(val label: String) {
|
||||||
|
WALLACH("Wallach"),
|
||||||
|
STUTE("Stute"),
|
||||||
|
HENGST("Hengst")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PferdeStatus(val label: String, val color: Color) {
|
||||||
|
AKTIV("Aktiv", Color(0xFF2E7D32)),
|
||||||
|
INAKTIV("Inaktiv", Color(0xFF757575)),
|
||||||
|
GESTOKEN("Gestorben", Color(0xFFC62828)),
|
||||||
|
VERKAUFT("Verkauft", Color(0xFF0277BD))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
package at.mocode.frontend.features.pferde.presentation
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import at.mocode.frontend.core.designsystem.components.*
|
||||||
|
import at.mocode.frontend.core.designsystem.models.PlaceholderContent
|
||||||
|
import at.mocode.frontend.features.pferde.domain.Geschlecht
|
||||||
|
import at.mocode.frontend.features.pferde.domain.Pferd
|
||||||
|
import at.mocode.frontend.features.pferde.domain.PferdeStatus
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PferdeScreen(
|
||||||
|
viewModel: PferdeViewModel = PferdeViewModel()
|
||||||
|
) {
|
||||||
|
val uiState = viewModel.uiState
|
||||||
|
|
||||||
|
MsMasterDetailLayout(
|
||||||
|
master = {
|
||||||
|
PferdeListContent(
|
||||||
|
uiState = uiState,
|
||||||
|
onSearchChange = viewModel::onSearchQueryChange,
|
||||||
|
onPferdSelected = viewModel::selectPferd
|
||||||
|
)
|
||||||
|
},
|
||||||
|
detail = {
|
||||||
|
if (uiState.isEditing) {
|
||||||
|
PferdeEditorContent(
|
||||||
|
uiState = uiState,
|
||||||
|
onNameChange = viewModel::onEditNameChange,
|
||||||
|
onLebensnummerChange = viewModel::onEditLebensnummerChange,
|
||||||
|
onGeschlechtChange = viewModel::onEditGeschlechtChange,
|
||||||
|
onFarbeChange = viewModel::onEditFarbeChange,
|
||||||
|
onGeburtsjahrChange = viewModel::onEditGeburtsjahrChange,
|
||||||
|
onStatusChange = viewModel::onEditStatusChange,
|
||||||
|
onSave = viewModel::onSave,
|
||||||
|
onCancel = viewModel::onCancel
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
PlaceholderContent(
|
||||||
|
title = "Kein Pferd ausgewählt",
|
||||||
|
subtitle = "Wählen Sie ein Pferd aus der Liste aus oder legen Sie ein neues an."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PferdeListContent(
|
||||||
|
uiState: PferdeUiState,
|
||||||
|
onSearchChange: (String) -> Unit,
|
||||||
|
onPferdSelected: (Pferd) -> Unit
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
|
MsFilterBar(
|
||||||
|
searchQuery = uiState.searchQuery,
|
||||||
|
onSearchQueryChange = onSearchChange,
|
||||||
|
resultCount = uiState.searchResults.size
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
|
||||||
|
MsDataTable(
|
||||||
|
items = uiState.searchResults,
|
||||||
|
columns = listOf(
|
||||||
|
MsColumnDefinition(
|
||||||
|
title = "Name",
|
||||||
|
weight = 1f,
|
||||||
|
cellRenderer = { Text(it.name, style = MaterialTheme.typography.bodySmall) }
|
||||||
|
),
|
||||||
|
MsColumnDefinition(
|
||||||
|
title = "Lebensnummer",
|
||||||
|
width = 150.dp,
|
||||||
|
cellRenderer = { Text(it.lebensnummer, style = MaterialTheme.typography.bodySmall) }
|
||||||
|
),
|
||||||
|
MsColumnDefinition(
|
||||||
|
title = "Status",
|
||||||
|
width = 100.dp,
|
||||||
|
cellRenderer = {
|
||||||
|
MsStatusBadge(
|
||||||
|
text = it.status.label,
|
||||||
|
containerColor = it.status.color.copy(alpha = 0.1f),
|
||||||
|
contentColor = it.status.color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
onRowClick = onPferdSelected
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PferdeEditorContent(
|
||||||
|
uiState: PferdeUiState,
|
||||||
|
onNameChange: (String) -> Unit,
|
||||||
|
onLebensnummerChange: (String) -> Unit,
|
||||||
|
onGeschlechtChange: (Geschlecht) -> Unit,
|
||||||
|
onFarbeChange: (String) -> Unit,
|
||||||
|
onGeburtsjahrChange: (String) -> Unit,
|
||||||
|
onStatusChange: (PferdeStatus) -> Unit,
|
||||||
|
onSave: () -> Unit,
|
||||||
|
onCancel: () -> Unit
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
|
MsActionToolbar(
|
||||||
|
title = "Pferde Details",
|
||||||
|
onSave = onSave,
|
||||||
|
onCancel = onCancel
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(Modifier.height(24.dp))
|
||||||
|
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
MsTextField(
|
||||||
|
value = uiState.editName,
|
||||||
|
onValueChange = onNameChange,
|
||||||
|
label = "Name",
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
MsTextField(
|
||||||
|
value = uiState.editLebensnummer,
|
||||||
|
onValueChange = onLebensnummerChange,
|
||||||
|
label = "Lebensnummer",
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
MsEnumDropdown(
|
||||||
|
label = "Geschlecht",
|
||||||
|
options = Geschlecht.entries.toTypedArray(),
|
||||||
|
selectedOption = uiState.editGeschlecht,
|
||||||
|
onOptionSelected = onGeschlechtChange,
|
||||||
|
optionLabel = { it.label },
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
MsTextField(
|
||||||
|
value = uiState.editFarbe,
|
||||||
|
onValueChange = onFarbeChange,
|
||||||
|
label = "Farbe",
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
MsTextField(
|
||||||
|
value = uiState.editGeburtsjahr,
|
||||||
|
onValueChange = onGeburtsjahrChange,
|
||||||
|
label = "Geburtsjahr",
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
MsEnumDropdown(
|
||||||
|
label = "Status",
|
||||||
|
options = PferdeStatus.entries.toTypedArray(),
|
||||||
|
selectedOption = uiState.editStatus,
|
||||||
|
onOptionSelected = onStatusChange,
|
||||||
|
optionLabel = { it.label },
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.height(24.dp))
|
||||||
|
|
||||||
|
if (uiState.editStatus == PferdeStatus.INAKTIV) {
|
||||||
|
MsValidationWrapper(
|
||||||
|
messages = listOf(
|
||||||
|
ValidationMessage(
|
||||||
|
"Pferd ist als inaktiv markiert und kann nicht für Nennungen verwendet werden.",
|
||||||
|
ValidationSeverity.WARNING
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Zusätzliche Pferde-Informationen",
|
||||||
|
style = MaterialTheme.typography.titleSmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In-Place Preview für den PferdeScreen.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun PferdeScreenPreviewContent() {
|
||||||
|
val viewModel = PferdeViewModel()
|
||||||
|
at.mocode.frontend.core.designsystem.theme.AppTheme {
|
||||||
|
Surface {
|
||||||
|
PferdeScreen(viewModel = viewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package at.mocode.frontend.features.pferde.presentation
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import at.mocode.frontend.features.pferde.domain.Geschlecht
|
||||||
|
import at.mocode.frontend.features.pferde.domain.Pferd
|
||||||
|
import at.mocode.frontend.features.pferde.domain.PferdeStatus
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI-State für die Pferde-Verwaltung.
|
||||||
|
*/
|
||||||
|
data class PferdeUiState(
|
||||||
|
val searchResults: List<Pferd> = emptyList(),
|
||||||
|
val searchQuery: String = "",
|
||||||
|
val selectedPferd: Pferd? = null,
|
||||||
|
val isEditing: Boolean = false,
|
||||||
|
val isLoading: Boolean = false,
|
||||||
|
val editName: String = "",
|
||||||
|
val editLebensnummer: String = "",
|
||||||
|
val editGeschlecht: Geschlecht = Geschlecht.WALLACH,
|
||||||
|
val editFarbe: String = "",
|
||||||
|
val editGeburtsjahr: String = "",
|
||||||
|
val editStatus: PferdeStatus = PferdeStatus.AKTIV
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewModel für die Pferde-Verwaltung.
|
||||||
|
*/
|
||||||
|
open class PferdeViewModel(initialLoad: Boolean = true) {
|
||||||
|
var uiState by mutableStateOf(PferdeUiState())
|
||||||
|
protected set
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (initialLoad) {
|
||||||
|
loadPferde()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
uiState = uiState.copy(searchResults = mockData)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSearchQueryChange(query: String) {
|
||||||
|
uiState = uiState.copy(searchQuery = query)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun selectPferd(pferd: Pferd) {
|
||||||
|
uiState = uiState.copy(
|
||||||
|
selectedPferd = pferd,
|
||||||
|
isEditing = true,
|
||||||
|
editName = pferd.name,
|
||||||
|
editLebensnummer = pferd.lebensnummer,
|
||||||
|
editGeschlecht = pferd.geschlecht,
|
||||||
|
editFarbe = pferd.farbe,
|
||||||
|
editGeburtsjahr = pferd.geburtsjahr?.toString() ?: "",
|
||||||
|
editStatus = pferd.status
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEditNameChange(value: String) {
|
||||||
|
uiState = uiState.copy(editName = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEditLebensnummerChange(value: String) {
|
||||||
|
uiState = uiState.copy(editLebensnummer = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEditGeschlechtChange(value: Geschlecht) {
|
||||||
|
uiState = uiState.copy(editGeschlecht = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEditFarbeChange(value: String) {
|
||||||
|
uiState = uiState.copy(editFarbe = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEditGeburtsjahrChange(value: String) {
|
||||||
|
uiState = uiState.copy(editGeburtsjahr = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEditStatusChange(value: PferdeStatus) {
|
||||||
|
uiState = uiState.copy(editStatus = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSave() {
|
||||||
|
uiState = uiState.copy(isEditing = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onCancel() {
|
||||||
|
uiState = uiState.copy(isEditing = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -136,7 +136,7 @@ private fun ReiterEditorContent(
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
MsEnumDropdown(
|
MsEnumDropdown(
|
||||||
label = "Lizenzklasse",
|
label = "Lizenzklasse",
|
||||||
options = LizenzKlasse.values(),
|
options = LizenzKlasse.entries.toTypedArray(),
|
||||||
selectedOption = uiState.editLizenz,
|
selectedOption = uiState.editLizenz,
|
||||||
onOptionSelected = onLizenzChange,
|
onOptionSelected = onLizenzChange,
|
||||||
optionLabel = { it.label },
|
optionLabel = { it.label },
|
||||||
|
|
@ -144,7 +144,7 @@ private fun ReiterEditorContent(
|
||||||
)
|
)
|
||||||
MsEnumDropdown(
|
MsEnumDropdown(
|
||||||
label = "Hauptsparte",
|
label = "Hauptsparte",
|
||||||
options = Sparte.values(),
|
options = Sparte.entries.toTypedArray(),
|
||||||
selectedOption = uiState.editSparte,
|
selectedOption = uiState.editSparte,
|
||||||
onOptionSelected = onSparteChange,
|
onOptionSelected = onSparteChange,
|
||||||
optionLabel = { it.label },
|
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.
|
* ViewModel für die Reiter-Verwaltung.
|
||||||
* In einem echten Szenario würden wir hier ein Repository injizieren.
|
* In einem echten Szenario würden wir hier ein Repository injizieren.
|
||||||
*/
|
*/
|
||||||
class ReiterViewModel {
|
open class ReiterViewModel(initialLoad: Boolean = true) {
|
||||||
var uiState by mutableStateOf(ReiterUiState())
|
var uiState by mutableStateOf(ReiterUiState())
|
||||||
private set
|
protected set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Initialer Load (Mock-Daten)
|
if (initialLoad) {
|
||||||
loadReiter()
|
// Initialer Load (Mock-Daten)
|
||||||
|
loadReiter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,8 @@ kotlin {
|
||||||
implementation(projects.frontend.features.veranstaltungFeature)
|
implementation(projects.frontend.features.veranstaltungFeature)
|
||||||
implementation(projects.frontend.features.turnierFeature)
|
implementation(projects.frontend.features.turnierFeature)
|
||||||
implementation(project(":frontend:features:profile-feature"))
|
implementation(project(":frontend:features:profile-feature"))
|
||||||
|
implementation(project(":frontend:features:reiter-feature"))
|
||||||
|
implementation(project(":frontend:features:pferde-feature"))
|
||||||
implementation(project(":frontend:features:billing-feature"))
|
implementation(project(":frontend:features:billing-feature"))
|
||||||
|
|
||||||
// Compose Desktop
|
// Compose Desktop
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,8 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.window.singleWindowApplication
|
import androidx.compose.ui.window.singleWindowApplication
|
||||||
import at.mocode.turnier.feature.presentation.TurnierDetailScreen
|
import at.mocode.frontend.features.pferde.presentation.PferdeScreen
|
||||||
import at.mocode.veranstalter.feature.presentation.VeranstalterAuswahlScreen
|
import at.mocode.frontend.features.pferde.presentation.PferdeViewModel
|
||||||
import at.mocode.veranstalter.feature.presentation.VeranstalterDetailScreen
|
|
||||||
import at.mocode.veranstalter.feature.presentation.VeranstalterNeuScreen
|
|
||||||
import at.mocode.veranstaltung.feature.presentation.AdminUebersichtScreen
|
|
||||||
import at.mocode.veranstaltung.feature.presentation.VeranstaltungUebersichtScreen
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hot-Reload Preview Entry Point
|
* Hot-Reload Preview Entry Point
|
||||||
|
|
@ -31,6 +27,13 @@ fun main() = singleWindowApplication(title = "🔥 Hot-Reload Preview") {
|
||||||
private fun PreviewContent() {
|
private fun PreviewContent() {
|
||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
Surface {
|
Surface {
|
||||||
|
|
||||||
|
// --- REITER ---
|
||||||
|
// ReiterScreen(viewModel = ReiterViewModel())
|
||||||
|
|
||||||
|
// --- PFERDE ---
|
||||||
|
PferdeScreen(viewModel = PferdeViewModel())
|
||||||
|
|
||||||
// ── Hier den gewünschten Screen eintragen ──────────────────────
|
// ── Hier den gewünschten Screen eintragen ──────────────────────
|
||||||
// VeranstalterAuswahlScreen(onVeranstalterSelected = {}, onNeuerVeranstalter = {})
|
// VeranstalterAuswahlScreen(onVeranstalterSelected = {}, onNeuerVeranstalter = {})
|
||||||
// VeranstalterNeuScreen(onBack = {}, onSave = {})
|
// VeranstalterNeuScreen(onBack = {}, onSave = {})
|
||||||
|
|
@ -40,11 +43,11 @@ private fun PreviewContent() {
|
||||||
// ──────────────────────────────────────────────────────────────
|
// ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
// Standard: AdminUebersichtScreen (Startseite nach Login)
|
// Standard: AdminUebersichtScreen (Startseite nach Login)
|
||||||
AdminUebersichtScreen(
|
// AdminUebersichtScreen(
|
||||||
onVeranstalterAuswahl = {},
|
// onVeranstalterAuswahl = {},
|
||||||
onVeranstaltungOeffnen = {},
|
// onVeranstaltungOeffnen = {},
|
||||||
onPingService = {}
|
// onPingService = {}
|
||||||
)
|
// )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ include(":frontend:features:veranstalter-feature")
|
||||||
include(":frontend:features:veranstaltung-feature")
|
include(":frontend:features:veranstaltung-feature")
|
||||||
include(":frontend:features:profile-feature")
|
include(":frontend:features:profile-feature")
|
||||||
include(":frontend:features:reiter-feature")
|
include(":frontend:features:reiter-feature")
|
||||||
|
include(":frontend:features:pferde-feature")
|
||||||
include(":frontend:features:turnier-feature")
|
include(":frontend:features:turnier-feature")
|
||||||
include(":frontend:features:billing-feature")
|
include(":frontend:features:billing-feature")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user