From 931fe7badb48486c1f4012ac4e0d0bc3db221aad Mon Sep 17 00:00:00 2001 From: Stefan Mogeritsch Date: Thu, 19 Mar 2026 12:10:17 +0100 Subject: [PATCH] refactor(ui): update app title, footer text, and layout spacing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- ...9_Session_Log_Frontend_Transfer_Offline.md | 65 +++++ .../core/designsystem/components/AppFooter.kt | 6 +- .../src/commonMain/kotlin/MainApp.kt | 261 ++++++++++++++---- .../src/jvmMain/kotlin/main.kt | 18 +- 4 files changed, 280 insertions(+), 70 deletions(-) create mode 100644 docs/99_Journal/2026-03-19_Session_Log_Frontend_Transfer_Offline.md diff --git a/docs/99_Journal/2026-03-19_Session_Log_Frontend_Transfer_Offline.md b/docs/99_Journal/2026-03-19_Session_Log_Frontend_Transfer_Offline.md new file mode 100644 index 00000000..3e3d91e8 --- /dev/null +++ b/docs/99_Journal/2026-03-19_Session_Log_Frontend_Transfer_Offline.md @@ -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). diff --git a/frontend/core/design-system/src/commonMain/kotlin/at/mocode/frontend/core/designsystem/components/AppFooter.kt b/frontend/core/design-system/src/commonMain/kotlin/at/mocode/frontend/core/designsystem/components/AppFooter.kt index 2897bb2b..a8d288b1 100644 --- a/frontend/core/design-system/src/commonMain/kotlin/at/mocode/frontend/core/designsystem/components/AppFooter.kt +++ b/frontend/core/design-system/src/commonMain/kotlin/at/mocode/frontend/core/designsystem/components/AppFooter.kt @@ -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 diff --git a/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt b/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt index 062cdd80..616d1604 100644 --- a/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt +++ b/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt @@ -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) } } diff --git a/frontend/shells/meldestelle-portal/src/jvmMain/kotlin/main.kt b/frontend/shells/meldestelle-portal/src/jvmMain/kotlin/main.kt index 0f1db1f1..820fde1c 100644 --- a/frontend/shells/meldestelle-portal/src/jvmMain/kotlin/main.kt +++ b/frontend/shells/meldestelle-portal/src/jvmMain/kotlin/main.kt @@ -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()