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

- 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:
Stefan Mogeritsch 2026-03-19 12:10:17 +01:00
parent 32295bdea2
commit 931fe7badb
4 changed files with 280 additions and 70 deletions

View File

@ -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).

View File

@ -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

View File

@ -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)
}
}

View File

@ -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()