refactor(ui): update app title, footer text, and layout spacing
All checks were successful
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Successful in 7m39s
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Successful in 7m21s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Successful in 3m15s
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Successful in 1m45s
All checks were successful
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Successful in 7m39s
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Successful in 7m21s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Successful in 3m15s
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Successful in 1m45s
- Changed the app title to "Equest-Events Master Desktop" in `main.kt`. - Updated footer text with new phrasing: "© Mocode-Software · Developed with love for equestrian sports". - Improved code formatting for consistent alignment and indentation across files. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
parent
32295bdea2
commit
931fe7badb
|
|
@ -0,0 +1,65 @@
|
|||
# Session Log: 19.03.2026 - Frontend "Turnier anlegen" & Offline-Architektur
|
||||
|
||||
**Teilnehmer:** Owner, 🏗️ [Lead Architect], 📜 [ÖTO/FEI Rulebook Expert], 👷 [Backend Developer], 🎨 [Frontend Expert],
|
||||
🧹 [Curator]
|
||||
|
||||
## Ziel der Session
|
||||
|
||||
Erweiterung des Frontend-Konzepts für den Turnieranlage-Wizard (Setup) mit besonderem Fokus auf harte Offline-Szenarien,
|
||||
Datenbank-Trennung pro Turnier, Synchronisation via USB-Stick und der architektonischen Trennung zwischen Web-App und
|
||||
Master-Desktop-App.
|
||||
|
||||
## Ergebnisse & Beschlüsse
|
||||
|
||||
### 1. Trennung: Web-App vs. "Equest-Events Master Desktop"
|
||||
|
||||
Es wurde eine klare architektonische Trennung der Clients beschlossen, die auf den Fähigkeiten von Compose
|
||||
Multiplatform (KMP) basiert:
|
||||
|
||||
* **Web-App (mo-code.at):** Dient als zentrale Anlaufstelle. Für die Öffentlichkeit (Ausschreibungen, Nennungen durch
|
||||
Reiter) und als leichtgewichtiges "Meldestellen Dashboard" zur Übersicht. Sie benötigt keine komplexen lokalen
|
||||
Datenbanken (Service Worker) für die Startseite.
|
||||
* **Desktop-App ("Equest-Events Master Desktop"):** Eine herunterladbare, native Anwendung (.exe / .app). Dies ist das "
|
||||
Profi-Werkzeug" für die Meldestelle vor Ort.
|
||||
* *Nur* die Desktop-App hat volle Rechte auf das Dateisystem (OS-Ebene), um z.B. direkt auf USB-Sticks zuzugreifen.
|
||||
* Sie beinhaltet exklusiv die "Admin-Features": Turnieranlage, ZNS-Import, OEPS-Export und die Initialisierung der
|
||||
lokalen Offline-Datenbank (SQLite).
|
||||
* Der Download-Link für diese Master-App ist direkt im Web-Dashboard für authentifizierte Meldestellen-Admins
|
||||
integriert.
|
||||
|
||||
### 2. Hardcore Offline-First & Turnier-Datenbanken
|
||||
|
||||
* **Isolierte Datenbanken:** Um extreme Offline-Szenarien (kein Internet, kein lokales Netzwerk, "Plumpsklo"-Setup)
|
||||
abzusichern, wird bei der Turnieranlage pro Turnier eine eigenständige, isolierte Datenbank (Turnier-Instanz)
|
||||
initialisiert.
|
||||
* **USB-Stick Synchronisation:** Die Master-Desktop-App muss in der Lage sein, diese Turnier-Datenbank komplett über das
|
||||
Dateisystem zu exportieren und auf einem anderen Gerät (z.B. Desktop-App am Richterturm) wieder zu importieren. Es
|
||||
gibt einen manuellen Sync-Prozess (Im-/Export) von Start- und Ergebnislisten via USB-Stick, falls WLAN/LAN ausfallen.
|
||||
* **Spezifizierung Dateipfade im UI:** Der "Transfer"-Schritt im UI wurde verfeinert. Statt abstrakter Buttons gibt es
|
||||
nun klare Eingabefelder für Datei- und Ordnerpfade inkl. File-Picker-Buttons (`...`), um den Desktop-Charakter der
|
||||
Anwendung zu unterstreichen.
|
||||
|
||||
### 3. Fremddaten, Y- & Z-Nummern
|
||||
|
||||
* **Regelwerks-Bestätigung:** Der Rulebook Expert bestätigte, dass die Vergabe von **Y-Nummern** (junge nationale Pferde
|
||||
ohne Registrierung) und **Z-Nummern** (ausländische Pferde) für *alle* nationalen Turniere gilt, nicht nur für C-NEU.
|
||||
* **Manuelle Anlage:** Das System unterstützt zwingend die nahtlose manuelle Anlage dieser Pferde und Reiter, die nicht
|
||||
im ZNS existieren (z.B. Gäste aus CZ). Diese manuellen Anlagen erfolgen auf Basis der isolierten Turnier-Datenbank.
|
||||
|
||||
### 4. UI-Erweiterung: Der neue "Transfer"-Schritt im Wizard
|
||||
|
||||
Der geführte Wizard zum Anlegen eines Turniers in der Desktop-App (`MainApp.kt`) wurde um den essenziellen ersten
|
||||
Schritt erweitert: **"Transfer & Initialisierung"**.
|
||||
Dieser Schritt fungiert als technische Schaltzentrale und beinhaltet:
|
||||
|
||||
* Initialisierung der Turnier-Datenbank (OEPS Nummer).
|
||||
* ZNS-Daten Import (OEPS) & Import von externen Zucht-Daten (z.B. AWÖ) via Dateiauswahl.
|
||||
* OEPS-Ergebnis-Export (Generierung der `.erg` Datei nach Turnierende) via Dateiauswahl.
|
||||
* Manuelle Up-/Downloads für den USB-Stick Sync (Turnier Export / Import) via Verzeichnisauswahl.
|
||||
|
||||
## Aktualisierte Dokumente
|
||||
|
||||
* `frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt` (Fünfstufiger Wizard mit detailliertem "
|
||||
Transfer"-Schritt und File-Picker Mockups implementiert. Dashboard-Hinweis auf Desktop-App Download hinzugefügt).
|
||||
* `frontend/shells/meldestelle-portal/src/jvmMain/kotlin/main.kt` (Titel der Desktop-Anwendung auf "Equest-Events Master
|
||||
Desktop" geändert).
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package at.mocode.frontend.core.designsystem.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -20,7 +22,7 @@ fun AppFooter() {
|
|||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "© Equest-Events · Entwickelt in Österreich",
|
||||
text = "© Mocode-Software · Developed with love for equestrian sports",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ fun MainApp() {
|
|||
is AppScreen.Dashboard -> DashboardScreen(
|
||||
authTokenManager = authTokenManager,
|
||||
onOpenPing = { navigationPort.navigateToScreen(AppScreen.Ping) },
|
||||
onCreateTournament = { navigationPort.navigateToScreen(AppScreen.CreateTournament) },
|
||||
onLogout = {
|
||||
authTokenManager.clearToken()
|
||||
navigationPort.navigateToScreen(AppScreen.Landing)
|
||||
|
|
@ -56,7 +55,6 @@ fun MainApp() {
|
|||
is AppScreen.Home -> DashboardScreen( // Route /home to Dashboard for now
|
||||
authTokenManager = authTokenManager,
|
||||
onOpenPing = { navigationPort.navigateToScreen(AppScreen.Ping) },
|
||||
onCreateTournament = { navigationPort.navigateToScreen(AppScreen.CreateTournament) },
|
||||
onLogout = {
|
||||
authTokenManager.clearToken()
|
||||
navigationPort.navigateToScreen(AppScreen.Landing)
|
||||
|
|
@ -358,7 +356,6 @@ private fun FeatureCard(number: String, title: String, body: String) {
|
|||
private fun DashboardScreen(
|
||||
authTokenManager: AuthTokenManager,
|
||||
onOpenPing: () -> Unit,
|
||||
onCreateTournament: () -> Unit,
|
||||
onLogout: () -> Unit
|
||||
) {
|
||||
val authState by authTokenManager.authState.collectAsState()
|
||||
|
|
@ -447,11 +444,42 @@ private fun DashboardScreen(
|
|||
}
|
||||
}
|
||||
|
||||
OutlinedButton(
|
||||
onClick = onCreateTournament,
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 16.dp)
|
||||
// DEIN NEUES KONZEPT: Download Desktop App statt "Neues Turnier anlegen" im Web
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.secondaryContainer)
|
||||
) {
|
||||
Text("+ Neues Turnier anlegen")
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(
|
||||
"Master-Meldestelle Desktop App",
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer
|
||||
)
|
||||
Text(
|
||||
"Für die Turnieranlage, den ZNS-Import und vollen Offline-Betrieb (USB-Sync) laden Sie bitte die Desktop-Anwendung herunter.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
) {
|
||||
Button(onClick = { /* TODO: Download Trigger */ }) {
|
||||
Text("Download für Windows (.exe)")
|
||||
}
|
||||
// Status Anzeige
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
Surface(
|
||||
modifier = Modifier.size(12.dp),
|
||||
shape = MaterialTheme.shapes.small,
|
||||
color = MaterialTheme.colorScheme.error
|
||||
) {}
|
||||
Text("Desktop App derzeit Offline", style = MaterialTheme.typography.labelMedium)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -470,13 +498,6 @@ private fun DashboardScreen(
|
|||
) {
|
||||
Text("Ping-Service (System Status)")
|
||||
}
|
||||
|
||||
OutlinedButton(
|
||||
onClick = { /* TODO: ZNS Import */ },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("ZNS-Daten Importieren")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -509,7 +530,7 @@ fun CreateTournamentScreen(
|
|||
Text("← Zurück")
|
||||
}
|
||||
Text(
|
||||
text = "Neues Turnier anlegen",
|
||||
text = "Neues Turnier anlegen (Desktop Client)",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
|
@ -523,20 +544,22 @@ fun CreateTournamentScreen(
|
|||
modifier = Modifier.padding(16.dp).fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
StepIndicator(step = 1, title = "Stammdaten", isActive = currentStep == 1, isCompleted = currentStep > 1)
|
||||
StepIndicator(step = 2, title = "Konfiguration", isActive = currentStep == 2, isCompleted = currentStep > 2)
|
||||
StepIndicator(step = 3, title = "Funktionäre", isActive = currentStep == 3, isCompleted = currentStep > 3)
|
||||
StepIndicator(step = 4, title = "Bewerbe", isActive = currentStep == 4, isCompleted = currentStep > 4)
|
||||
StepIndicator(step = 1, title = "Transfer", isActive = currentStep == 1, isCompleted = currentStep > 1)
|
||||
StepIndicator(step = 2, title = "Stammdaten", isActive = currentStep == 2, isCompleted = currentStep > 2)
|
||||
StepIndicator(step = 3, title = "Konfiguration", isActive = currentStep == 3, isCompleted = currentStep > 3)
|
||||
StepIndicator(step = 4, title = "Funktionäre", isActive = currentStep == 4, isCompleted = currentStep > 4)
|
||||
StepIndicator(step = 5, title = "Bewerbe", isActive = currentStep == 5, isCompleted = currentStep > 5)
|
||||
}
|
||||
}
|
||||
|
||||
// Wizard Content Area
|
||||
Box(modifier = Modifier.weight(1f).padding(24.dp)) {
|
||||
when (currentStep) {
|
||||
1 -> TournamentStepStammdaten()
|
||||
2 -> TournamentStepKonfiguration()
|
||||
3 -> TournamentStepFunktionaere()
|
||||
4 -> TournamentStepBewerbe()
|
||||
1 -> TournamentStepTransfer()
|
||||
2 -> TournamentStepStammdaten()
|
||||
3 -> TournamentStepKonfiguration()
|
||||
4 -> TournamentStepFunktionaere()
|
||||
5 -> TournamentStepBewerbe()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -552,7 +575,7 @@ fun CreateTournamentScreen(
|
|||
Spacer(modifier = Modifier.width(1.dp)) // Empty space to keep "Weiter" on the right
|
||||
}
|
||||
|
||||
if (currentStep < 4) {
|
||||
if (currentStep < 5) {
|
||||
Button(onClick = { currentStep++ }) { Text("Weiter") }
|
||||
} else {
|
||||
Button(onClick = onSave) { Text("Turnier speichern") }
|
||||
|
|
@ -586,56 +609,167 @@ fun StepIndicator(step: Int, title: String, isActive: Boolean, isCompleted: Bool
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun TournamentStepStammdaten() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxWidth(0.6f)) {
|
||||
Text("Schritt 1: Turnier-Stammdaten", style = MaterialTheme.typography.headlineSmall)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Turniernummer OEPS (z.B. 26128)") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Turniername (z.B. CSN-C NEU Neumarkt)") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
fun TournamentStepTransfer() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(24.dp), modifier = Modifier.fillMaxWidth(0.8f)) {
|
||||
Text("Schritt 1: Transfer & Initialisierung", style = MaterialTheme.typography.headlineSmall)
|
||||
Text(
|
||||
"In diesem Schritt erschaffen wir eine separate Datenbank für dieses spezifische Turnier. " +
|
||||
"Diese Datenbank kann für den komplett isolierten Offline-Betrieb (z.B. am USB-Stick) auf andere Laptops übertragen werden.",
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxWidth()) {
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Turniernummer OEPS (z.B. 26128)") },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Button(onClick = { /*TODO*/ }, modifier = Modifier.align(Alignment.CenterVertically)) {
|
||||
Text("Turnierdatenbank Initialisieren")
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))
|
||||
|
||||
Text("Datenaustausch (OEPS / Externe Systeme)", style = MaterialTheme.typography.titleMedium)
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
Card(modifier = Modifier.weight(1f)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Text("ZNS / Stammdaten Import", fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
"Aktualisieren Sie die Reiter, Pferde und Funktionäre aus dem zentralen System.",
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Pfad zur ZNS.zip") },
|
||||
modifier = Modifier.weight(1f),
|
||||
readOnly = true
|
||||
)
|
||||
Button(onClick = { /* Öffnet File Picker */ }) { Text("...") }
|
||||
}
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Pfad zur AWÖ/Zucht-Datei") },
|
||||
modifier = Modifier.weight(1f),
|
||||
readOnly = true
|
||||
)
|
||||
Button(onClick = { /* Öffnet File Picker */ }) { Text("...") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Card(modifier = Modifier.weight(1f)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Text("OEPS Export", fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
"Erzeugt die xxxxx.erg Datei für die offizielle Ergebnismeldung nach dem Turnier.",
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Ziel-Ordner für .erg Export") },
|
||||
modifier = Modifier.weight(1f),
|
||||
readOnly = true
|
||||
)
|
||||
Button(onClick = { /* Öffnet Directory Picker */ }) { Text("...") }
|
||||
}
|
||||
Button(
|
||||
onClick = { /*TODO*/ },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
enabled = false
|
||||
) { Text("Ergebnis-Export (.erg)") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))
|
||||
|
||||
Text("Offline-Sync (USB-Stick / Lokales Netzwerk)", style = MaterialTheme.typography.titleMedium)
|
||||
Text(
|
||||
"Übertragen Sie den kompletten Turnierstand zwischen Master-Meldestelle und Richterturm-Laptops ohne Internet.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
// Export (Speichern auf Stick)
|
||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Ziel-Pfad (z.B. D:/Export)") },
|
||||
modifier = Modifier.weight(1f),
|
||||
readOnly = true
|
||||
)
|
||||
Button(onClick = { /* Öffnet Directory Picker */ }) { Text("...") }
|
||||
}
|
||||
OutlinedButton(onClick = { /*TODO*/ }, modifier = Modifier.fillMaxWidth()) { Text("↑ Turnier Exportieren") }
|
||||
}
|
||||
|
||||
// Import (Lesen vom Stick)
|
||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
label = { Text("Quell-Datei (z.B. D:/turnier.db)") },
|
||||
modifier = Modifier.weight(1f),
|
||||
readOnly = true
|
||||
)
|
||||
Button(onClick = { /* Öffnet File Picker */ }) { Text("...") }
|
||||
}
|
||||
OutlinedButton(onClick = { /*TODO*/ }, modifier = Modifier.fillMaxWidth()) { Text("↓ Turnier Importieren") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TournamentStepStammdaten() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxWidth(0.6f)) {
|
||||
Text("Schritt 2: Turnier-Stammdaten", style = MaterialTheme.typography.headlineSmall)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "CSN-C NEU Neumarkt", // Dummy pre-fill
|
||||
onValueChange = {},
|
||||
label = { Text("Turniername") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxWidth()) {
|
||||
OutlinedTextField(
|
||||
value = "25.04.2026",
|
||||
onValueChange = {},
|
||||
label = { Text("Datum von") },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
value = "25.04.2026",
|
||||
onValueChange = {},
|
||||
label = { Text("Datum bis") },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
|
||||
Card(modifier = Modifier.fillMaxWidth()) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text("ZNS Import", fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
"Hier laden wir später das ZNS.zip für dieses Turnier hoch, um Starter und Lizenzen zu importieren.",
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Button(onClick = { /*TODO*/ }) { Text("ZNS.zip auswählen...") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TournamentStepKonfiguration() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxWidth(0.6f)) {
|
||||
Text("Schritt 2: Konfiguration", style = MaterialTheme.typography.headlineSmall)
|
||||
Text("Schritt 3: Konfiguration", style = MaterialTheme.typography.headlineSmall)
|
||||
Text("Austragungsplätze und Preisliste")
|
||||
|
||||
// Placeholder for Austragungsplätze
|
||||
|
|
@ -643,8 +777,8 @@ fun TournamentStepKonfiguration() {
|
|||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text("Austragungsplätze", fontWeight = FontWeight.Bold)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = 8.dp)) {
|
||||
FilterChip(selected = true, onClick = {}, label = { Text("Platz 1 (Sand)") })
|
||||
FilterChip(selected = false, onClick = {}, label = { Text("Halle") })
|
||||
FilterChip(selected = true, onClick = {}, label = { Text("Platz 1 (Sand/Vlies 45x65m)") })
|
||||
FilterChip(selected = false, onClick = {}, label = { Text("Halle (Sand/Vlies 20x40m)") })
|
||||
FilterChip(selected = false, onClick = {}, label = { Text("+ Hinzufügen") })
|
||||
}
|
||||
}
|
||||
|
|
@ -655,29 +789,36 @@ fun TournamentStepKonfiguration() {
|
|||
@Composable
|
||||
fun TournamentStepFunktionaere() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxWidth(0.6f)) {
|
||||
Text("Schritt 3: Team & Funktionäre", style = MaterialTheme.typography.headlineSmall)
|
||||
Text("Schritt 4: Team & Funktionäre", style = MaterialTheme.typography.headlineSmall)
|
||||
Text("Zuweisung von Richtern und Parcoursbauern (aus ZNS)")
|
||||
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
value = "Rudi Kreupl",
|
||||
onValueChange = {},
|
||||
label = { Text("Turnierbeauftragter (Suche nach Name oder ID)") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
value = "Helmut Riedler",
|
||||
onValueChange = {},
|
||||
label = { Text("Richter (Suche nach Name oder ID)") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = "Kurt Reitetschlägerr",
|
||||
onValueChange = {},
|
||||
label = { Text("Parcoursbauchef") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TournamentStepBewerbe() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxSize()) {
|
||||
Text("Schritt 4: Bewerbe anlegen", style = MaterialTheme.typography.headlineSmall)
|
||||
Text("Schritt 5: Bewerbe anlegen", style = MaterialTheme.typography.headlineSmall)
|
||||
|
||||
Row(modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
// Left: List of Bewerbe
|
||||
|
|
@ -690,6 +831,8 @@ fun TournamentStepBewerbe() {
|
|||
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))
|
||||
Text("1: Pony Stilspringprüfung (60cm)", modifier = Modifier.padding(vertical = 4.dp))
|
||||
Text("2: Einlaufspringprüfung (60cm)", modifier = Modifier.padding(vertical = 4.dp))
|
||||
Text("3: Pony Stilspringprüfung (70cm)", modifier = Modifier.padding(vertical = 4.dp))
|
||||
Text("4: Einlaufspringprüfung (70cm)", modifier = Modifier.padding(vertical = 4.dp))
|
||||
Text("...", modifier = Modifier.padding(vertical = 4.dp), color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
import androidx.compose.ui.window.WindowState
|
||||
import androidx.compose.ui.unit.dp
|
||||
import at.mocode.frontend.core.network.networkModule
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.WindowState
|
||||
import androidx.compose.ui.window.application
|
||||
import at.mocode.frontend.core.auth.di.authModule
|
||||
import at.mocode.frontend.core.sync.di.syncModule
|
||||
import at.mocode.ping.feature.di.pingFeatureModule
|
||||
import at.mocode.frontend.core.localdb.AppDatabase
|
||||
import at.mocode.frontend.core.localdb.DatabaseProvider
|
||||
import at.mocode.frontend.core.localdb.localDbModule
|
||||
import navigation.navigationModule
|
||||
import at.mocode.frontend.core.network.networkModule
|
||||
import at.mocode.frontend.core.sync.di.syncModule
|
||||
import at.mocode.ping.feature.di.pingFeatureModule
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.koin.core.context.startKoin
|
||||
import navigation.navigationModule
|
||||
import org.koin.core.context.loadKoinModules
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.dsl.module
|
||||
|
||||
fun main() = application {
|
||||
|
|
@ -40,7 +40,7 @@ fun main() = application {
|
|||
}
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "Meldestelle - Desktop Development",
|
||||
title = "Equest-Events Master Desktop",
|
||||
state = WindowState(width = 1200.dp, height = 800.dp)
|
||||
) {
|
||||
MainApp()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user