chore: refactor TurnierDetailScreen and related components, remove unused parameters, centralize date validation logic, implement TurnierStammdatenViewModel, and eliminate reflection dependencies

This commit is contained in:
2026-04-20 10:11:07 +02:00
parent f8820847fa
commit 2489beab59
8 changed files with 350 additions and 171 deletions
@@ -43,8 +43,7 @@ import at.mocode.frontend.features.profile.presentation.ProfileScreen
import at.mocode.frontend.features.profile.presentation.ProfileViewModel
import at.mocode.frontend.features.reiter.presentation.ReiterScreen
import at.mocode.frontend.features.reiter.presentation.ReiterViewModel
import at.mocode.frontend.features.turnier.presentation.SeriesScreen
import at.mocode.frontend.features.turnier.presentation.TurnierDetailScreen
import at.mocode.frontend.features.turnier.presentation.*
import at.mocode.frontend.features.veranstalter.presentation.VeranstaltungKonfigScreen
import at.mocode.frontend.features.verein.presentation.VereinScreen
import at.mocode.frontend.features.verein.presentation.VereinViewModel
@@ -66,6 +65,7 @@ import at.mocode.veranstaltung.feature.presentation.VeranstaltungNeuScreen
import kotlinx.coroutines.delay
import org.koin.compose.koinInject
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.parameter.parametersOf
import kotlin.time.Duration.Companion.milliseconds
// Primärfarbe der TopBar (kann später ins Theme ausgelagert werden)
@@ -589,7 +589,7 @@ private fun DesktopContentArea(
is AppScreen.DeviceInitialization -> {
println("[Screen] Rendering DeviceInitialization")
val viewModel = koinViewModel<DeviceInitializationViewModel> {
org.koin.core.parameter.parametersOf({ finalSettings: DeviceInitializationSettings ->
parametersOf({ finalSettings: DeviceInitializationSettings ->
DeviceInitializationSettingsManager.saveSettings(finalSettings)
// Vision_04: Sicherheitsschlüssel als Token setzen, damit Cloud-Suche funktioniert
val authTokenManager =
@@ -837,10 +837,17 @@ private fun DesktopContentArea(
val veranstaltung = Store.eventsFor(parent.id).firstOrNull { it.id == evtId }
val blCode = parent.oepsNummer.split("-").getOrNull(1) ?: ""
val bundesland = mapOepsToBundesland(blCode)
val bewerbViewModel: BewerbViewModel = koinInject { parametersOf(currentScreen.turnierId) }
val nennungViewModel: TurnierNennungViewModel = koinInject { parametersOf(currentScreen.turnierId) }
val stammdatenViewModel: TurnierStammdatenViewModel = koinInject()
TurnierDetailScreen(
veranstaltungId = evtId,
turnierId = currentScreen.turnierId,
onBack = onBack,
bewerbViewModel = bewerbViewModel,
nennungViewModel = nennungViewModel,
stammdatenViewModel = stammdatenViewModel,
eventVon = veranstaltung?.datumVon,
eventBis = veranstaltung?.datumBis,
eventOrt = veranstaltung?.ort,
@@ -902,14 +909,6 @@ private fun DesktopContentArea(
)
}
is AppScreen.Vereine -> {
println("[Screen] Rendering Vereine (VereinScreen)")
val vereinViewModel: VereinViewModel = koinViewModel()
VereinScreen(
viewModel = vereinViewModel
)
}
// --- Billing ---
is AppScreen.Billing -> {
val billingViewModel: BillingViewModel = koinViewModel()
@@ -3,15 +3,15 @@ package at.mocode.frontend.shell.desktop.screens.preview
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import at.mocode.frontend.core.designsystem.preview.ComponentPreview
import at.mocode.frontend.features.turnier.domain.*
import at.mocode.frontend.features.turnier.presentation.*
import at.mocode.frontend.features.turnier.data.remote.dto.NennungEinreichenRequest
import at.mocode.zns.parser.ZnsBewerb
import at.mocode.frontend.features.turnier.domain.*
import at.mocode.frontend.features.turnier.domain.model.StartlistenZeile
import at.mocode.frontend.features.turnier.presentation.*
import at.mocode.frontend.features.veranstalter.presentation.VeranstalterAuswahlScreen
import at.mocode.frontend.features.veranstalter.presentation.VeranstalterDetailScreen
import at.mocode.frontend.features.veranstalter.presentation.VeranstalterNeuScreen
import at.mocode.frontend.features.turnier.domain.model.StartlistenZeile
import at.mocode.veranstaltung.feature.presentation.VeranstaltungUebersichtScreen
import at.mocode.zns.parser.ZnsBewerb
// ─────────────────────────────────────────────────────────────────────────────
// Compose Desktop Previews alle wichtigen Screens auf einen Blick
@@ -86,11 +86,69 @@ fun PreviewVeranstaltungUebersichtScreen() {
@ComponentPreview
@Composable
fun PreviewTurnierDetailScreen() {
val mockTurnierRepo = object : TurnierRepository {
override suspend fun list(): Result<List<Turnier>> = Result.success(emptyList())
override suspend fun getById(id: Long): Result<Turnier> = Result.success(Turnier(id, "Test Turnier"))
override suspend fun create(model: Turnier): Result<Turnier> = Result.success(model)
override suspend fun update(id: Long, model: Turnier): Result<Turnier> = Result.success(model)
override suspend fun delete(id: Long): Result<Unit> = Result.success(Unit)
}
val mockBewerbRepo = object : BewerbRepository {
override suspend fun list(turnierId: Long): Result<List<Bewerb>> = Result.success(emptyList())
override suspend fun getById(id: Long): Result<Bewerb> = Result.failure(NotImplementedError())
override suspend fun create(model: Bewerb): Result<Bewerb> = Result.failure(NotImplementedError())
override suspend fun update(id: Long, model: Bewerb): Result<Bewerb> = Result.failure(NotImplementedError())
override suspend fun delete(id: Long): Result<Unit> = Result.success(Unit)
override suspend fun updateZeitplan(id: Long, datum: String?, beginn: String?, platzId: String?): Result<Bewerb> =
Result.failure(NotImplementedError())
override suspend fun getAuditLog(bewerbId: Long): Result<List<AuditLogEntry>> = Result.success(emptyList())
override suspend fun exportZnsBSatz(turnierId: Long): Result<String> = Result.success("")
override suspend fun importBewerbe(turnierId: Long, bewerbe: List<ZnsBewerb>): Result<Unit> = Result.success(Unit)
}
val mockStartlistenRepo = object : StartlistenRepository {
override suspend fun generate(bewerbId: Long): Result<List<StartlistenZeile>> = Result.success(emptyList())
override suspend fun getByBewerb(bewerbId: Long): Result<List<StartlistenZeile>> = Result.success(emptyList())
}
val mockErgebnisRepo = object : ErgebnisRepository {
override suspend fun getForBewerb(bewerbId: String): Result<List<Ergebnis>> = Result.success(emptyList())
override suspend fun save(ergebnis: Ergebnis): Result<Ergebnis> = Result.success(ergebnis)
override suspend fun calculatePlatzierung(bewerbId: String): Result<List<Ergebnis>> = Result.success(emptyList())
override suspend fun exportPdf(bewerbId: String): Result<ByteArray> = Result.success(ByteArray(0))
}
val bewerbVm = BewerbViewModel(mockBewerbRepo, mockStartlistenRepo, mockErgebnisRepo, null, 1L)
val mockNennungRepo = object : NennungRepository {
override suspend fun list(turnierId: Long): Result<List<Nennung>> = Result.success(emptyList())
override suspend fun listByBewerb(bewerbId: Long): Result<List<Nennung>> = Result.success(emptyList())
override suspend fun einreichen(request: NennungEinreichenRequest): Result<Nennung> =
Result.failure(NotImplementedError())
override suspend fun updateStatus(id: String, status: String): Result<Nennung> =
Result.failure(NotImplementedError())
override suspend fun delete(id: String): Result<Unit> = Result.success(Unit)
}
val mockMasterdataRepo = object : MasterdataRepository {
override suspend fun searchReiter(query: String): Result<List<Reiter>> = Result.success(emptyList())
override suspend fun searchPferde(query: String): Result<List<Pferd>> = Result.success(emptyList())
override suspend fun getReiter(id: String): Result<Reiter> = Result.failure(NotImplementedError())
override suspend fun saveReiter(reiter: Reiter): Result<Reiter> = Result.success(reiter)
override suspend fun getPferd(id: String): Result<Pferd> = Result.failure(NotImplementedError())
override suspend fun savePferd(pferd: Pferd): Result<Pferd> = Result.success(pferd)
override suspend fun searchFunktionaere(query: String): Result<List<Funktionaer>> = Result.success(emptyList())
override suspend fun listVereine(): Result<List<Verein>> = Result.success(emptyList())
override suspend fun getVereinById(id: String): Result<Verein> = Result.failure(NotImplementedError())
}
val nennungVm = TurnierNennungViewModel(mockNennungRepo, mockMasterdataRepo, 1L)
val stammdatenVm = TurnierStammdatenViewModel(mockTurnierRepo)
MaterialTheme {
TurnierDetailScreen(
veranstaltungId = 1L,
turnierId = 1L,
onBack = {},
bewerbViewModel = bewerbVm,
nennungViewModel = nennungVm,
stammdatenViewModel = stammdatenVm,
)
}
}
@@ -100,8 +158,16 @@ fun PreviewTurnierDetailScreen() {
@ComponentPreview
@Composable
fun PreviewTurnierStammdatenTab() {
val mockTurnierRepo = object : TurnierRepository {
override suspend fun list(): Result<List<Turnier>> = Result.success(emptyList())
override suspend fun getById(id: Long): Result<Turnier> = Result.success(Turnier(id, "Test Turnier"))
override suspend fun create(model: Turnier): Result<Turnier> = Result.success(model)
override suspend fun update(id: Long, model: Turnier): Result<Turnier> = Result.success(model)
override suspend fun delete(id: Long): Result<Unit> = Result.success(Unit)
}
val vm = TurnierStammdatenViewModel(mockTurnierRepo)
MaterialTheme {
StammdatenTabContent(turnierId = 1L)
StammdatenTabContent(turnierId = 1L, viewModel = vm)
}
}
@@ -111,8 +177,12 @@ fun PreviewTurnierOrganisationTab() {
val mockNennungRepo = object : NennungRepository {
override suspend fun list(turnierId: Long): Result<List<Nennung>> = Result.success(emptyList())
override suspend fun listByBewerb(bewerbId: Long): Result<List<Nennung>> = Result.success(emptyList())
override suspend fun einreichen(request: NennungEinreichenRequest): Result<Nennung> = Result.failure(NotImplementedError())
override suspend fun updateStatus(id: String, status: String): Result<Nennung> = Result.failure(NotImplementedError())
override suspend fun einreichen(request: NennungEinreichenRequest): Result<Nennung> =
Result.failure(NotImplementedError())
override suspend fun updateStatus(id: String, status: String): Result<Nennung> =
Result.failure(NotImplementedError())
override suspend fun delete(id: String): Result<Unit> = Result.success(Unit)
}
val mockMasterdataRepo = object : MasterdataRepository {
@@ -141,9 +211,13 @@ fun PreviewTurnierBewerbeTab() {
override suspend fun create(model: Bewerb): Result<Bewerb> = Result.failure(NotImplementedError())
override suspend fun update(id: Long, model: Bewerb): Result<Bewerb> = Result.failure(NotImplementedError())
override suspend fun delete(id: Long): Result<Unit> = Result.success(Unit)
override suspend fun updateZeitplan(id: Long, datum: String?, beginn: String?, platzId: String?): Result<Bewerb> = Result.failure(NotImplementedError())
override suspend fun updateZeitplan(id: Long, datum: String?, beginn: String?, platzId: String?): Result<Bewerb> =
Result.failure(NotImplementedError())
override suspend fun getAuditLog(bewerbId: Long): Result<List<AuditLogEntry>> = Result.success(emptyList())
override suspend fun exportZnsBSatz(turnierId: Long): Result<String> = Result.success("BBEWERBE\r\n B0100Bewerb 1 A01 20260411001\r\n")
override suspend fun exportZnsBSatz(turnierId: Long): Result<String> =
Result.success("BBEWERBE\r\n B0100Bewerb 1 A01 20260411001\r\n")
override suspend fun importBewerbe(turnierId: Long, bewerbe: List<ZnsBewerb>): Result<Unit> = Result.success(Unit)
}
val mockStartlistenRepo = object : StartlistenRepository {
@@ -190,8 +264,12 @@ fun PreviewTurnierNennungenTab() {
val mockNennungRepo = object : NennungRepository {
override suspend fun list(turnierId: Long): Result<List<Nennung>> = Result.success(emptyList())
override suspend fun listByBewerb(bewerbId: Long): Result<List<Nennung>> = Result.success(emptyList())
override suspend fun einreichen(request: NennungEinreichenRequest): Result<Nennung> = Result.failure(NotImplementedError())
override suspend fun updateStatus(id: String, status: String): Result<Nennung> = Result.failure(NotImplementedError())
override suspend fun einreichen(request: NennungEinreichenRequest): Result<Nennung> =
Result.failure(NotImplementedError())
override suspend fun updateStatus(id: String, status: String): Result<Nennung> =
Result.failure(NotImplementedError())
override suspend fun delete(id: String): Result<Unit> = Result.success(Unit)
}
val mockMasterdataRepo = object : MasterdataRepository {