refactor(desktop): V2-Suffixe entfernt und VeranstaltungKomponenten modularisiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
parent
0128f98164
commit
3949ab21db
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Session Journal: 2026-04-17 - Aufräumarbeiten & Konsolidierung
|
||||||
|
|
||||||
|
## 🎯 Ziele der Session
|
||||||
|
|
||||||
|
1. **V2-Cleanup:** Entfernung aller `V2`-Suffixe aus dem Codebase (Modelle, Stores, Wizards), um eine konsolidierte "
|
||||||
|
Source of Truth" zu schaffen.
|
||||||
|
2. **Refactoring:** Zerlegung der massiven `VeranstaltungKonfig`-Komponente in wartbare Teil-Module.
|
||||||
|
3. **Duplikat-Entfernung:** Zentralisierung von UI-Logik (DatePicker, Validierung) zur Reduzierung von Code-Duplikaten.
|
||||||
|
|
||||||
|
## 🛠️ Durchgeführte Änderungen
|
||||||
|
|
||||||
|
### 🧹 1. Konsolidierung der Benamung (V2-Entfernung)
|
||||||
|
|
||||||
|
* **Änderungen:**
|
||||||
|
* `VeranstaltungKonfigV2` -> `VeranstaltungKonfig`
|
||||||
|
* `VeranstaltungV2` -> `Veranstaltung`
|
||||||
|
* `TurnierV2` -> `Turnier`
|
||||||
|
* `StoreV2` -> `Store`
|
||||||
|
* `TurnierStoreV2` -> `TurnierStore`
|
||||||
|
* `TurnierWizardV2` -> `TurnierWizard`
|
||||||
|
* **Grund:** Umsetzung der Vereinbarung, nur noch eine "echte" Version zu pflegen und Altlasten aus Migrationsphasen zu
|
||||||
|
entfernen. Alle Referenzen im gesamten Projekt (`DesktopMainLayout.kt`, `ManagementScreens.kt`, `main.kt`) wurden
|
||||||
|
erfolgreich aktualisiert.
|
||||||
|
|
||||||
|
### 🏗️ 2. Refactoring `VeranstaltungScreens.kt`
|
||||||
|
|
||||||
|
* **Extraktion:** Die Wizard-Schritte wurden in eigenständige Composable-Funktionen ausgelagert:
|
||||||
|
* `Step1Veranstalter`: Auswahl aus ZNS/Lokal-Bestand.
|
||||||
|
* `Step2Basisdaten`: Titel, Zeitraum, Ort, Disziplinen.
|
||||||
|
* `Step3Details`: Logo, Sponsoren, Bewerbs-Management.
|
||||||
|
* **Zentralisierung:**
|
||||||
|
* Neue Komponente `AppDatePickerDialog` zur Vermeidung von dreifach redundantem Dialog-Code.
|
||||||
|
* Konsolidierte Validierungslogik für den Veranstaltungszeitraum.
|
||||||
|
|
||||||
|
### 🏷️ 3. Fehlerbehebung & Qualitätssicherung
|
||||||
|
|
||||||
|
* **Syntax-Fix:** Korrektur von Klammerfehlern, die während des Refactorings in der großen `VeranstaltungScreens.kt`
|
||||||
|
entstanden sind.
|
||||||
|
* **Linting:** Erfolgreiche Validierung der Dateien `VeranstaltungScreens.kt`, `Stores.kt` und `DesktopMainLayout.kt`.
|
||||||
|
|
||||||
|
## ✅ Ergebnis & Status
|
||||||
|
|
||||||
|
* Der Code ist nun wesentlich modularer und besser lesbar.
|
||||||
|
* Die Benamung ist konsistent ohne verwirrende Versions-Suffixe.
|
||||||
|
* Redundante Logik-Blöcke (besonders beim Datum-Handling) wurden eliminiert.
|
||||||
|
|
||||||
|
---
|
||||||
|
**🏗️ [Lead Architect]** & **🧹 [Curator]**
|
||||||
|
Datum: 17. April 2026 | Status: Abgeschlossen
|
||||||
|
|
@ -50,11 +50,22 @@
|
||||||
* Anzeige der letzten Sync-Version (z.B. `ZNS: V12` oder `ZNS: Kein Sync`).
|
* Anzeige der letzten Sync-Version (z.B. `ZNS: V12` oder `ZNS: Kein Sync`).
|
||||||
* Farbliche Kennzeichnung (Grün/Gelb/Rot) je nach Synchronisationsstand.
|
* Farbliche Kennzeichnung (Grün/Gelb/Rot) je nach Synchronisationsstand.
|
||||||
|
|
||||||
|
### 🏗️ 5. Fachlich: Disziplinen & Bewerbe (Schritt 2 & 3)
|
||||||
|
|
||||||
|
* **Datei:** `frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/v2/VeranstaltungScreens.kt`
|
||||||
|
* **Änderung:**
|
||||||
|
* **Schritt 2:** Felder für PLZ und Disziplin-Auswahl (Springen, Dressur, etc.) hinzugefügt.
|
||||||
|
* **Schritt 3:** Komplettes Bewerbs-Management implementiert. User können Prüfungsnummern, Klassen und Bezeichnungen
|
||||||
|
erfassen.
|
||||||
|
* **Validierung:** Der Wizard lässt sich erst finalisieren, wenn mindestens ein Bewerb angelegt wurde.
|
||||||
|
* **Grund:** Vorbereitung der Datenstruktur für den OEPS-Export und Verbesserung der fachlichen Abdeckung im Wizard.
|
||||||
|
|
||||||
## ✅ Ergebnis & Status
|
## ✅ Ergebnis & Status
|
||||||
|
|
||||||
* Das Consul-Dashboard sollte nun einen stabilen "Grün"-Status für den `masterdata-service` anzeigen.
|
* Das Consul-Dashboard sollte nun einen stabilen "Grün"-Status für den `masterdata-service` anzeigen.
|
||||||
* Der Desktop-Wizard leitet den User fachlich korrekt durch die Turnier-Anlage.
|
* Der Desktop-Wizard leitet den User fachlich korrekt durch die Turnier-Anlage.
|
||||||
* Der User hat jederzeit volle Transparenz über den Stand seiner lokalen ZNS-Daten.
|
* Der User hat jederzeit volle Transparenz über den Stand seiner lokalen ZNS-Daten.
|
||||||
|
* Die Erfassung von Bewerben legt den Grundstein für die spätere Nennungs- und Ergebnisverwaltung.
|
||||||
|
|
||||||
---
|
---
|
||||||
**🏗️ [Lead Architect]** & **🧹 [Curator]**
|
**🏗️ [Lead Architect]** & **🧹 [Curator]**
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ import at.mocode.frontend.core.localdb.localDbModule
|
||||||
import at.mocode.frontend.core.network.networkModule
|
import at.mocode.frontend.core.network.networkModule
|
||||||
import at.mocode.frontend.core.sync.di.syncModule
|
import at.mocode.frontend.core.sync.di.syncModule
|
||||||
import at.mocode.frontend.features.billing.di.billingModule
|
import at.mocode.frontend.features.billing.di.billingModule
|
||||||
import at.mocode.frontend.features.profile.di.profileModule
|
|
||||||
import at.mocode.frontend.features.verein.di.vereinFeatureModule
|
|
||||||
import at.mocode.frontend.features.nennung.di.nennungFeatureModule
|
import at.mocode.frontend.features.nennung.di.nennungFeatureModule
|
||||||
import at.mocode.frontend.features.pferde.di.pferdeModule
|
import at.mocode.frontend.features.pferde.di.pferdeModule
|
||||||
|
import at.mocode.frontend.features.profile.di.profileModule
|
||||||
import at.mocode.frontend.features.reiter.di.reiterModule
|
import at.mocode.frontend.features.reiter.di.reiterModule
|
||||||
import at.mocode.turnier.feature.di.turnierFeatureModule
|
import at.mocode.frontend.features.verein.di.vereinFeatureModule
|
||||||
import at.mocode.ping.feature.di.pingFeatureModule
|
import at.mocode.ping.feature.di.pingFeatureModule
|
||||||
|
import at.mocode.turnier.feature.di.turnierFeatureModule
|
||||||
import at.mocode.zns.feature.di.znsImportModule
|
import at.mocode.zns.feature.di.znsImportModule
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.koin.core.context.GlobalContext
|
import org.koin.core.context.GlobalContext
|
||||||
|
|
@ -48,7 +48,7 @@ fun main() = application {
|
||||||
}
|
}
|
||||||
println("[DesktopApp] KOIN initialisiert")
|
println("[DesktopApp] KOIN initialisiert")
|
||||||
// Testdaten für Prototyp laden
|
// Testdaten für Prototyp laden
|
||||||
at.mocode.desktop.v2.StoreV2.seed()
|
at.mocode.desktop.v2.Store.seed()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("[DesktopApp] Koin-Warnung: ${e.message}")
|
println("[DesktopApp] Koin-Warnung: ${e.message}")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -660,7 +660,7 @@ private fun DesktopContentArea(
|
||||||
is AppScreen.VeranstaltungKonfig -> {
|
is AppScreen.VeranstaltungKonfig -> {
|
||||||
val vId = currentScreen.veranstalterId
|
val vId = currentScreen.veranstalterId
|
||||||
// Falls vId == 0, kommen wir aus der Gesamtübersicht und wählen erst im Wizard
|
// Falls vId == 0, kommen wir aus der Gesamtübersicht und wählen erst im Wizard
|
||||||
at.mocode.desktop.v2.VeranstaltungKonfigV2(
|
at.mocode.desktop.v2.VeranstaltungKonfig(
|
||||||
veranstalterId = vId,
|
veranstalterId = vId,
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onSaved = { evtId, finalVId -> onNavigate(AppScreen.VeranstaltungProfil(finalVId, evtId)) },
|
onSaved = { evtId, finalVId -> onNavigate(AppScreen.VeranstaltungProfil(finalVId, evtId)) },
|
||||||
|
|
@ -671,12 +671,12 @@ private fun DesktopContentArea(
|
||||||
is AppScreen.VeranstaltungProfil -> {
|
is AppScreen.VeranstaltungProfil -> {
|
||||||
val vId = currentScreen.veranstalterId
|
val vId = currentScreen.veranstalterId
|
||||||
val evtId = currentScreen.veranstaltungId
|
val evtId = currentScreen.veranstaltungId
|
||||||
if (at.mocode.desktop.v2.StoreV2.vereine.none { it.id == vId }) {
|
if (at.mocode.desktop.v2.Store.vereine.none { it.id == vId }) {
|
||||||
InvalidContextNotice(
|
InvalidContextNotice(
|
||||||
message = "Veranstalter (ID=$vId) nicht gefunden.",
|
message = "Veranstalter (ID=$vId) nicht gefunden.",
|
||||||
onBack = onBack
|
onBack = onBack
|
||||||
)
|
)
|
||||||
} else if (at.mocode.desktop.v2.StoreV2.eventsFor(vId).none { it.id == evtId }) {
|
} else if (at.mocode.desktop.v2.Store.eventsFor(vId).none { it.id == evtId }) {
|
||||||
InvalidContextNotice(
|
InvalidContextNotice(
|
||||||
message = "Veranstaltung (ID=$evtId) gehört nicht zu Veranstalter #$vId.",
|
message = "Veranstaltung (ID=$evtId) gehört nicht zu Veranstalter #$vId.",
|
||||||
onBack = onBack
|
onBack = onBack
|
||||||
|
|
@ -687,17 +687,17 @@ private fun DesktopContentArea(
|
||||||
veranstaltungId = evtId,
|
veranstaltungId = evtId,
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onTurnierNeu = {
|
onTurnierNeu = {
|
||||||
val veranstaltung = at.mocode.desktop.v2.StoreV2.eventsFor(vId).firstOrNull { it.id == evtId }
|
val veranstaltung = at.mocode.desktop.v2.Store.eventsFor(vId).firstOrNull { it.id == evtId }
|
||||||
val list = at.mocode.desktop.v2.TurnierStoreV2.list(evtId)
|
val list = at.mocode.desktop.v2.TurnierStore.list(evtId)
|
||||||
val newId = (list.maxOfOrNull { it.id } ?: 0L) + 1L
|
val newId = (list.maxOfOrNull { it.id } ?: 0L) + 1L
|
||||||
val draft = at.mocode.desktop.v2.TurnierV2(
|
val draft = at.mocode.desktop.v2.Turnier(
|
||||||
id = newId,
|
id = newId,
|
||||||
veranstaltungId = evtId,
|
veranstaltungId = evtId,
|
||||||
turnierNr = 0,
|
turnierNr = 0,
|
||||||
datumVon = veranstaltung?.datumVon ?: "",
|
datumVon = veranstaltung?.datumVon ?: "",
|
||||||
datumBis = veranstaltung?.datumBis,
|
datumBis = veranstaltung?.datumBis,
|
||||||
)
|
)
|
||||||
at.mocode.desktop.v2.TurnierStoreV2.add(evtId, draft)
|
at.mocode.desktop.v2.TurnierStore.add(evtId, draft)
|
||||||
onNavigate(AppScreen.TurnierDetail(evtId, newId))
|
onNavigate(AppScreen.TurnierDetail(evtId, newId))
|
||||||
},
|
},
|
||||||
onTurnierOpen = { tId -> onNavigate(AppScreen.TurnierDetail(evtId, tId)) },
|
onTurnierOpen = { tId -> onNavigate(AppScreen.TurnierDetail(evtId, tId)) },
|
||||||
|
|
@ -711,21 +711,21 @@ private fun DesktopContentArea(
|
||||||
veranstaltungId = currentScreen.id,
|
veranstaltungId = currentScreen.id,
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onTurnierNeu = {
|
onTurnierNeu = {
|
||||||
val v = at.mocode.desktop.v2.StoreV2.vereine.firstOrNull { vv ->
|
val v = at.mocode.desktop.v2.Store.vereine.firstOrNull { vv ->
|
||||||
at.mocode.desktop.v2.StoreV2.eventsFor(vv.id).any { it.id == currentScreen.id }
|
at.mocode.desktop.v2.Store.eventsFor(vv.id).any { it.id == currentScreen.id }
|
||||||
}
|
}
|
||||||
val veranstaltung =
|
val veranstaltung =
|
||||||
v?.let { at.mocode.desktop.v2.StoreV2.eventsFor(it.id).firstOrNull { e -> e.id == currentScreen.id } }
|
v?.let { at.mocode.desktop.v2.Store.eventsFor(it.id).firstOrNull { e -> e.id == currentScreen.id } }
|
||||||
val list = at.mocode.desktop.v2.TurnierStoreV2.list(currentScreen.id)
|
val list = at.mocode.desktop.v2.TurnierStore.list(currentScreen.id)
|
||||||
val newId = (list.maxOfOrNull { it.id } ?: 0L) + 1L
|
val newId = (list.maxOfOrNull { it.id } ?: 0L) + 1L
|
||||||
val draft = at.mocode.desktop.v2.TurnierV2(
|
val draft = at.mocode.desktop.v2.Turnier(
|
||||||
id = newId,
|
id = newId,
|
||||||
veranstaltungId = currentScreen.id,
|
veranstaltungId = currentScreen.id,
|
||||||
turnierNr = 0,
|
turnierNr = 0,
|
||||||
datumVon = veranstaltung?.datumVon ?: "",
|
datumVon = veranstaltung?.datumVon ?: "",
|
||||||
datumBis = veranstaltung?.datumBis,
|
datumBis = veranstaltung?.datumBis,
|
||||||
)
|
)
|
||||||
at.mocode.desktop.v2.TurnierStoreV2.add(currentScreen.id, draft)
|
at.mocode.desktop.v2.TurnierStore.add(currentScreen.id, draft)
|
||||||
onNavigate(AppScreen.TurnierDetail(currentScreen.id, newId))
|
onNavigate(AppScreen.TurnierDetail(currentScreen.id, newId))
|
||||||
},
|
},
|
||||||
onTurnierOeffnen = { tid -> onNavigate(AppScreen.TurnierDetail(currentScreen.id, tid)) },
|
onTurnierOeffnen = { tid -> onNavigate(AppScreen.TurnierDetail(currentScreen.id, tid)) },
|
||||||
|
|
@ -739,8 +739,8 @@ private fun DesktopContentArea(
|
||||||
// Turnier-Screens
|
// Turnier-Screens
|
||||||
is AppScreen.TurnierDetail -> {
|
is AppScreen.TurnierDetail -> {
|
||||||
val evtId = currentScreen.veranstaltungId
|
val evtId = currentScreen.veranstaltungId
|
||||||
val parent = at.mocode.desktop.v2.StoreV2.vereine.firstOrNull { v ->
|
val parent = at.mocode.desktop.v2.Store.vereine.firstOrNull { v ->
|
||||||
at.mocode.desktop.v2.StoreV2.eventsFor(v.id).any { it.id == evtId }
|
at.mocode.desktop.v2.Store.eventsFor(v.id).any { it.id == evtId }
|
||||||
}
|
}
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
InvalidContextNotice(
|
InvalidContextNotice(
|
||||||
|
|
@ -748,7 +748,7 @@ private fun DesktopContentArea(
|
||||||
onBack = onBack
|
onBack = onBack
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val veranstaltung = at.mocode.desktop.v2.StoreV2.eventsFor(parent.id).firstOrNull { it.id == evtId }
|
val veranstaltung = at.mocode.desktop.v2.Store.eventsFor(parent.id).firstOrNull { it.id == evtId }
|
||||||
val blCode = parent.oepsNummer.split("-").getOrNull(1) ?: ""
|
val blCode = parent.oepsNummer.split("-").getOrNull(1) ?: ""
|
||||||
val bundesland = mapOepsToBundesland(blCode)
|
val bundesland = mapOepsToBundesland(blCode)
|
||||||
TurnierDetailScreen(
|
TurnierDetailScreen(
|
||||||
|
|
@ -769,8 +769,8 @@ private fun DesktopContentArea(
|
||||||
is AppScreen.TurnierNeu -> {
|
is AppScreen.TurnierNeu -> {
|
||||||
val evtId = currentScreen.veranstaltungId
|
val evtId = currentScreen.veranstaltungId
|
||||||
// V2: Wir erlauben Turnier-Nr nur, wenn die Veranstaltung im V2-Store existiert
|
// V2: Wir erlauben Turnier-Nr nur, wenn die Veranstaltung im V2-Store existiert
|
||||||
val parent = at.mocode.desktop.v2.StoreV2.vereine.firstOrNull { v ->
|
val parent = at.mocode.desktop.v2.Store.vereine.firstOrNull { v ->
|
||||||
at.mocode.desktop.v2.StoreV2.eventsFor(v.id).any { it.id == evtId }
|
at.mocode.desktop.v2.Store.eventsFor(v.id).any { it.id == evtId }
|
||||||
}
|
}
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
InvalidContextNotice(
|
InvalidContextNotice(
|
||||||
|
|
@ -778,7 +778,7 @@ private fun DesktopContentArea(
|
||||||
onBack = onBack
|
onBack = onBack
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
at.mocode.desktop.v2.TurnierWizardV2(
|
at.mocode.desktop.v2.TurnierWizard(
|
||||||
veranstalterId = parent.id,
|
veranstalterId = parent.id,
|
||||||
veranstaltungId = evtId,
|
veranstaltungId = evtId,
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -140,7 +142,7 @@ data class TableColumn<T>(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PferdeVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
fun PferdeVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
val pferde = StoreV2.pferde
|
val pferde = Store.pferde
|
||||||
var filter by remember { mutableStateOf("") }
|
var filter by remember { mutableStateOf("") }
|
||||||
val filteredItems = if (filter.isEmpty()) pferde else pferde.filter {
|
val filteredItems = if (filter.isEmpty()) pferde else pferde.filter {
|
||||||
it.name.contains(filter, ignoreCase = true) || it.feiId?.contains(filter, ignoreCase = true) == true
|
it.name.contains(filter, ignoreCase = true) || it.feiId?.contains(filter, ignoreCase = true) == true
|
||||||
|
|
@ -162,14 +164,14 @@ fun PferdeVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onNew = { /* CRUD Logik */ },
|
onNew = { /* CRUD Logik */ },
|
||||||
onEdit = { onEdit(it.id) },
|
onEdit = { onEdit(it.id) },
|
||||||
onDelete = { StoreV2.pferde.remove(it) },
|
onDelete = { Store.pferde.remove(it) },
|
||||||
onSearch = { filter = it }
|
onSearch = { filter = it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReiterVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
fun ReiterVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
val reiter = StoreV2.reiter
|
val reiter = Store.reiter
|
||||||
var filter by remember { mutableStateOf("") }
|
var filter by remember { mutableStateOf("") }
|
||||||
val filteredItems = if (filter.isEmpty()) reiter else reiter.filter {
|
val filteredItems = if (filter.isEmpty()) reiter else reiter.filter {
|
||||||
it.vorname.contains(filter, ignoreCase = true) || it.nachname.contains(
|
it.vorname.contains(filter, ignoreCase = true) || it.nachname.contains(
|
||||||
|
|
@ -192,14 +194,14 @@ fun ReiterVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onNew = { },
|
onNew = { },
|
||||||
onEdit = { onEdit(it.id) },
|
onEdit = { onEdit(it.id) },
|
||||||
onDelete = { StoreV2.reiter.remove(it) },
|
onDelete = { Store.reiter.remove(it) },
|
||||||
onSearch = { filter = it }
|
onSearch = { filter = it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VereinVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
fun VereinVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
val vereine = StoreV2.vereine
|
val vereine = Store.vereine
|
||||||
var filter by remember { mutableStateOf("") }
|
var filter by remember { mutableStateOf("") }
|
||||||
val filteredItems = if (filter.isEmpty()) vereine else vereine.filter {
|
val filteredItems = if (filter.isEmpty()) vereine else vereine.filter {
|
||||||
it.name.contains(filter, ignoreCase = true) || it.oepsNummer.contains(filter, ignoreCase = true)
|
it.name.contains(filter, ignoreCase = true) || it.oepsNummer.contains(filter, ignoreCase = true)
|
||||||
|
|
@ -218,14 +220,14 @@ fun VereinVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onNew = { },
|
onNew = { },
|
||||||
onEdit = { onEdit(it.id) },
|
onEdit = { onEdit(it.id) },
|
||||||
onDelete = { StoreV2.vereine.remove(it) },
|
onDelete = { Store.vereine.remove(it) },
|
||||||
onSearch = { filter = it }
|
onSearch = { filter = it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FunktionaerVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
fun FunktionaerVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
val funktionaere = StoreV2.funktionaere
|
val funktionaere = Store.funktionaere
|
||||||
var filter by remember { mutableStateOf("") }
|
var filter by remember { mutableStateOf("") }
|
||||||
val filteredItems = if (filter.isEmpty()) funktionaere else funktionaere.filter {
|
val filteredItems = if (filter.isEmpty()) funktionaere else funktionaere.filter {
|
||||||
it.vorname.contains(filter, ignoreCase = true) || it.nachname.contains(filter, ignoreCase = true)
|
it.vorname.contains(filter, ignoreCase = true) || it.nachname.contains(filter, ignoreCase = true)
|
||||||
|
|
@ -244,7 +246,7 @@ fun FunktionaerVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onNew = { },
|
onNew = { },
|
||||||
onEdit = { onEdit(it.id) },
|
onEdit = { onEdit(it.id) },
|
||||||
onDelete = { StoreV2.funktionaere.remove(it) },
|
onDelete = { Store.funktionaere.remove(it) },
|
||||||
onSearch = { filter = it }
|
onSearch = { filter = it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -253,7 +255,7 @@ fun FunktionaerVerwaltungScreen(onBack: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
fun VeranstalterVerwaltungScreen(onBack: () -> Unit, onNew: () -> Unit, onEdit: (Long) -> Unit) {
|
fun VeranstalterVerwaltungScreen(onBack: () -> Unit, onNew: () -> Unit, onEdit: (Long) -> Unit) {
|
||||||
// Veranstalter sind in unserem System eigentlich Vereine, die Veranstaltungen ausrichten
|
// Veranstalter sind in unserem System eigentlich Vereine, die Veranstaltungen ausrichten
|
||||||
// Wir nutzen hier die 'vereine' Liste aus dem Store.
|
// Wir nutzen hier die 'vereine' Liste aus dem Store.
|
||||||
val vereine = StoreV2.vereine
|
val vereine = Store.vereine
|
||||||
var filter by remember { mutableStateOf("") }
|
var filter by remember { mutableStateOf("") }
|
||||||
val filteredItems = if (filter.isEmpty()) vereine else vereine.filter {
|
val filteredItems = if (filter.isEmpty()) vereine else vereine.filter {
|
||||||
it.name.contains(filter, ignoreCase = true) || it.oepsNummer.contains(filter, ignoreCase = true)
|
it.name.contains(filter, ignoreCase = true) || it.oepsNummer.contains(filter, ignoreCase = true)
|
||||||
|
|
|
||||||
|
|
@ -431,7 +431,7 @@ fun OnboardingScreenPreview() {
|
||||||
@Composable
|
@Composable
|
||||||
fun PferdProfilV2(id: Long, onBack: () -> Unit) {
|
fun PferdProfilV2(id: Long, onBack: () -> Unit) {
|
||||||
DesktopThemeV2 {
|
DesktopThemeV2 {
|
||||||
val pferd = remember(id) { StoreV2.pferde.firstOrNull { it.id == id } }
|
val pferd = remember(id) { Store.pferde.firstOrNull { it.id == id } }
|
||||||
if (pferd == null) {
|
if (pferd == null) {
|
||||||
Text("Pferd nicht gefunden"); return@DesktopThemeV2
|
Text("Pferd nicht gefunden"); return@DesktopThemeV2
|
||||||
}
|
}
|
||||||
|
|
@ -506,7 +506,7 @@ fun PferdProfilV2(id: Long, onBack: () -> Unit) {
|
||||||
@Composable
|
@Composable
|
||||||
fun ReiterProfilV2(id: Long, onBack: () -> Unit) {
|
fun ReiterProfilV2(id: Long, onBack: () -> Unit) {
|
||||||
DesktopThemeV2 {
|
DesktopThemeV2 {
|
||||||
val r = remember(id) { StoreV2.reiter.firstOrNull { it.id == id } }
|
val r = remember(id) { Store.reiter.firstOrNull { it.id == id } }
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
Text("Reiter nicht gefunden"); return@DesktopThemeV2
|
Text("Reiter nicht gefunden"); return@DesktopThemeV2
|
||||||
}
|
}
|
||||||
|
|
@ -590,7 +590,7 @@ fun ReiterProfilV2(id: Long, onBack: () -> Unit) {
|
||||||
@Composable
|
@Composable
|
||||||
fun VereinProfilV2(id: Long, onBack: () -> Unit) {
|
fun VereinProfilV2(id: Long, onBack: () -> Unit) {
|
||||||
DesktopThemeV2 {
|
DesktopThemeV2 {
|
||||||
val v = remember(id) { StoreV2.vereine.firstOrNull { it.id == id } }
|
val v = remember(id) { Store.vereine.firstOrNull { it.id == id } }
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
Text("Verein nicht gefunden"); return@DesktopThemeV2
|
Text("Verein nicht gefunden"); return@DesktopThemeV2
|
||||||
}
|
}
|
||||||
|
|
@ -681,7 +681,7 @@ fun VereinProfilV2(id: Long, onBack: () -> Unit) {
|
||||||
@Composable
|
@Composable
|
||||||
fun FunktionaerProfilV2(id: Long, onBack: () -> Unit) {
|
fun FunktionaerProfilV2(id: Long, onBack: () -> Unit) {
|
||||||
DesktopThemeV2 {
|
DesktopThemeV2 {
|
||||||
val f = remember(id) { StoreV2.funktionaere.firstOrNull { it.id == id } }
|
val f = remember(id) { Store.funktionaere.firstOrNull { it.id == id } }
|
||||||
if (f == null) {
|
if (f == null) {
|
||||||
Text("Funktionär nicht gefunden"); return@DesktopThemeV2
|
Text("Funktionär nicht gefunden"); return@DesktopThemeV2
|
||||||
}
|
}
|
||||||
|
|
@ -782,7 +782,7 @@ fun VeranstalterAuswahlV2(
|
||||||
var selectedId by remember { mutableStateOf<Long?>(null) }
|
var selectedId by remember { mutableStateOf<Long?>(null) }
|
||||||
|
|
||||||
LazyColumn(Modifier.fillMaxSize()) {
|
LazyColumn(Modifier.fillMaxSize()) {
|
||||||
items(StoreV2.vereine) { v ->
|
items(Store.vereine) { v ->
|
||||||
val sel = selectedId == v.id
|
val sel = selectedId == v.id
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -822,14 +822,14 @@ fun VeranstalterDetailV2(
|
||||||
Icons.AutoMirrored.Filled.ArrowBack,
|
Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
contentDescription = "Zurück",
|
contentDescription = "Zurück",
|
||||||
modifier = Modifier.clickable { onBack() })
|
modifier = Modifier.clickable { onBack() })
|
||||||
val verein = StoreV2.vereine.firstOrNull { it.id == veranstalterId }
|
val verein = Store.vereine.firstOrNull { it.id == veranstalterId }
|
||||||
Text(verein?.name ?: "Veranstalter", style = MaterialTheme.typography.titleLarge)
|
Text(verein?.name ?: "Veranstalter", style = MaterialTheme.typography.titleLarge)
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
Button(onClick = onNeuVeranstaltung) { Text("+ Neue Veranstaltung") }
|
Button(onClick = onNeuVeranstaltung) { Text("+ Neue Veranstaltung") }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Veranstalter Vorschau-Karte mit Bearbeiten-Dialog
|
// Veranstalter Vorschau-Karte mit Bearbeiten-Dialog
|
||||||
val verein = remember(veranstalterId) { StoreV2.vereine.firstOrNull { it.id == veranstalterId } }
|
val verein = remember(veranstalterId) { Store.vereine.firstOrNull { it.id == veranstalterId } }
|
||||||
if (verein != null) {
|
if (verein != null) {
|
||||||
var editOpen by remember { mutableStateOf(false) }
|
var editOpen by remember { mutableStateOf(false) }
|
||||||
Card(Modifier.fillMaxWidth()) {
|
Card(Modifier.fillMaxWidth()) {
|
||||||
|
|
@ -953,7 +953,7 @@ fun VeranstalterDetailV2(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val events = StoreV2.eventsFor(veranstalterId)
|
val events = Store.eventsFor(veranstalterId)
|
||||||
// Filter-/Suchmaske
|
// Filter-/Suchmaske
|
||||||
var search by remember { mutableStateOf("") }
|
var search by remember { mutableStateOf("") }
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
|
@ -992,7 +992,7 @@ fun VeranstalterDetailV2(
|
||||||
onDismissRequest = { confirm = false },
|
onDismissRequest = { confirm = false },
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = {
|
TextButton(onClick = {
|
||||||
StoreV2.removeEvent(veranstalterId, evt.id)
|
Store.removeEvent(veranstalterId, evt.id)
|
||||||
confirm = false
|
confirm = false
|
||||||
}) { Text("Löschen") }
|
}) { Text("Löschen") }
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ data class Funktionaer(
|
||||||
var istAktiv: Boolean = true,
|
var istAktiv: Boolean = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class VeranstaltungV2(
|
data class Veranstaltung(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
var veranstalterId: Long,
|
var veranstalterId: Long,
|
||||||
var titel: String,
|
var titel: String,
|
||||||
|
|
@ -85,7 +85,7 @@ data class VeranstaltungV2(
|
||||||
var sponsoren: SnapshotStateList<String> = mutableStateListOf(),
|
var sponsoren: SnapshotStateList<String> = mutableStateListOf(),
|
||||||
)
|
)
|
||||||
|
|
||||||
object StoreV2 {
|
object Store {
|
||||||
val pferde: SnapshotStateList<Pferd> = mutableStateListOf(
|
val pferde: SnapshotStateList<Pferd> = mutableStateListOf(
|
||||||
Pferd(
|
Pferd(
|
||||||
id = 1,
|
id = 1,
|
||||||
|
|
@ -268,7 +268,7 @@ object StoreV2 {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
private val veranstaltungen: MutableMap<Long, SnapshotStateList<VeranstaltungV2>> = mutableMapOf()
|
private val veranstaltungen: MutableMap<Long, SnapshotStateList<Veranstaltung>> = mutableMapOf()
|
||||||
|
|
||||||
fun seed() {
|
fun seed() {
|
||||||
// Falls bereits Daten da sind (außer den statischen Vereinen), nichts tun
|
// Falls bereits Daten da sind (außer den statischen Vereinen), nichts tun
|
||||||
|
|
@ -277,7 +277,7 @@ object StoreV2 {
|
||||||
// 1. Neumarkt April 2026 (ID 100)
|
// 1. Neumarkt April 2026 (ID 100)
|
||||||
val neumarktId = 100L
|
val neumarktId = 100L
|
||||||
addEventFirst(
|
addEventFirst(
|
||||||
1, VeranstaltungV2(
|
1, Veranstaltung(
|
||||||
id = neumarktId,
|
id = neumarktId,
|
||||||
veranstalterId = 1,
|
veranstalterId = 1,
|
||||||
titel = "CSN-B* Neumarkt am Wallersee",
|
titel = "CSN-B* Neumarkt am Wallersee",
|
||||||
|
|
@ -289,17 +289,17 @@ object StoreV2 {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
TurnierStoreV2.add(
|
TurnierStore.add(
|
||||||
neumarktId,
|
neumarktId,
|
||||||
TurnierV2(101, neumarktId, 26128, datumVon = "2026-04-24", datumBis = "2026-04-26", znsDataLoaded = true).apply {
|
Turnier(101, neumarktId, 26128, datumVon = "2026-04-24", datumBis = "2026-04-26", znsDataLoaded = true).apply {
|
||||||
titel = "Springturnier Neumarkt"
|
titel = "Springturnier Neumarkt"
|
||||||
kategorie.add("CSN-B*")
|
kategorie.add("CSN-B*")
|
||||||
kategorie.add("CSNP-B")
|
kategorie.add("CSNP-B")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
TurnierStoreV2.add(
|
TurnierStore.add(
|
||||||
neumarktId,
|
neumarktId,
|
||||||
TurnierV2(102, neumarktId, 26129, datumVon = "2026-04-24", datumBis = "2026-04-26", znsDataLoaded = true).apply {
|
Turnier(102, neumarktId, 26129, datumVon = "2026-04-24", datumBis = "2026-04-26", znsDataLoaded = true).apply {
|
||||||
titel = "Dressurturnier Neumarkt"
|
titel = "Dressurturnier Neumarkt"
|
||||||
kategorie.add("CDN-B")
|
kategorie.add("CDN-B")
|
||||||
kategorie.add("CDNP-B")
|
kategorie.add("CDNP-B")
|
||||||
|
|
@ -309,7 +309,7 @@ object StoreV2 {
|
||||||
// 2. Linz 2026 (ID 200)
|
// 2. Linz 2026 (ID 200)
|
||||||
val linzId = 200L
|
val linzId = 200L
|
||||||
addEventFirst(
|
addEventFirst(
|
||||||
2, VeranstaltungV2(
|
2, Veranstaltung(
|
||||||
id = linzId,
|
id = linzId,
|
||||||
veranstalterId = 2,
|
veranstalterId = 2,
|
||||||
titel = "Linzer Pferdefestival",
|
titel = "Linzer Pferdefestival",
|
||||||
|
|
@ -319,15 +319,15 @@ object StoreV2 {
|
||||||
beschreibung = "Große Reitsport-Veranstaltung am Ebelsberger Schlosspark."
|
beschreibung = "Große Reitsport-Veranstaltung am Ebelsberger Schlosspark."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
TurnierStoreV2.add(
|
TurnierStore.add(
|
||||||
linzId,
|
linzId,
|
||||||
TurnierV2(201, linzId, 26500, datumVon = "2026-05-20", datumBis = "2026-05-24", znsDataLoaded = true).apply {
|
Turnier(201, linzId, 26500, datumVon = "2026-05-20", datumBis = "2026-05-24", znsDataLoaded = true).apply {
|
||||||
kategorie.add("CSN-B*")
|
kategorie.add("CSN-B*")
|
||||||
})
|
})
|
||||||
|
|
||||||
// 3. Ein historisches Event (ID 300)
|
// 3. Ein historisches Event (ID 300)
|
||||||
addEventFirst(
|
addEventFirst(
|
||||||
1, VeranstaltungV2(
|
1, Veranstaltung(
|
||||||
id = 300L,
|
id = 300L,
|
||||||
veranstalterId = 1,
|
veranstalterId = 1,
|
||||||
titel = "Herbst-Turnier 2025",
|
titel = "Herbst-Turnier 2025",
|
||||||
|
|
@ -338,10 +338,10 @@ object StoreV2 {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun eventsFor(vereinId: Long): SnapshotStateList<VeranstaltungV2> =
|
fun eventsFor(vereinId: Long): SnapshotStateList<Veranstaltung> =
|
||||||
veranstaltungen.getOrPut(vereinId) { mutableStateListOf() }
|
veranstaltungen.getOrPut(vereinId) { mutableStateListOf() }
|
||||||
|
|
||||||
fun addEventFirst(vereinId: Long, v: VeranstaltungV2) {
|
fun addEventFirst(vereinId: Long, v: Veranstaltung) {
|
||||||
eventsFor(vereinId).add(0, v)
|
eventsFor(vereinId).add(0, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -351,5 +351,5 @@ object StoreV2 {
|
||||||
if (idx >= 0) list.removeAt(idx)
|
if (idx >= 0) list.removeAt(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun allEvents(): List<VeranstaltungV2> = veranstaltungen.values.flatten()
|
fun allEvents(): List<Veranstaltung> = veranstaltungen.values.flatten()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user