Implement MVVM for all V3 screens: add ViewModels for Turniere, Bewerbe, Abteilungen, Pferde, Reiter, Vereins, and Funktionaer workflows. Update roadmap to mark B-1 tasks as complete.

This commit is contained in:
2026-04-03 00:21:09 +02:00
parent 48ffadaaa2
commit 2b3e2d8c1b
8 changed files with 748 additions and 8 deletions
@@ -0,0 +1,99 @@
package at.mocode.frontend.features.pferde.presentation
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
data class PferdProfilState(
val isLoading: Boolean = false,
val errorMessage: String? = null,
val name: String = "",
val feiId: String = "",
val oepsNummer: String = "",
val geburtsjahr: String = "",
val farbe: String = "",
val rasse: String = "",
val validHints: List<String> = emptyList(),
val dirty: Boolean = false,
)
sealed interface PferdProfilIntent {
data class Load(val id: String) : PferdProfilIntent
data object Refresh : PferdProfilIntent
data class EditName(val v: String) : PferdProfilIntent
data class EditFeiId(val v: String) : PferdProfilIntent
data class EditOeps(val v: String) : PferdProfilIntent
data class EditGeburtsjahr(val v: String) : PferdProfilIntent
data class EditFarbe(val v: String) : PferdProfilIntent
data class EditRasse(val v: String) : PferdProfilIntent
data object Save : PferdProfilIntent
data object ClearError : PferdProfilIntent
}
interface PferdProfilRepository {
suspend fun load(id: String): PferdProfilState
suspend fun save(id: String, state: PferdProfilState)
}
class PferdProfilViewModel(
private val repo: PferdProfilRepository,
private var id: String,
) {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private val _state = MutableStateFlow(PferdProfilState(isLoading = true))
val state: StateFlow<PferdProfilState> = _state
init { send(PferdProfilIntent.Load(id)) }
fun send(intent: PferdProfilIntent) {
when (intent) {
is PferdProfilIntent.Load -> { id = intent.id; load() }
is PferdProfilIntent.Refresh -> load()
is PferdProfilIntent.EditName -> edit { it.copy(name = intent.v) }
is PferdProfilIntent.EditFeiId -> edit { it.copy(feiId = intent.v) }
is PferdProfilIntent.EditOeps -> edit { it.copy(oepsNummer = intent.v) }
is PferdProfilIntent.EditGeburtsjahr -> edit { it.copy(geburtsjahr = intent.v) }
is PferdProfilIntent.EditFarbe -> edit { it.copy(farbe = intent.v) }
is PferdProfilIntent.EditRasse -> edit { it.copy(rasse = intent.v) }
is PferdProfilIntent.Save -> save()
is PferdProfilIntent.ClearError -> reduce { it.copy(errorMessage = null) }
}
}
private fun load() {
reduce { it.copy(isLoading = true, errorMessage = null) }
scope.launch {
try {
val loaded = repo.load(id)
reduce { loaded.copy(isLoading = false, dirty = false) }
} catch (t: Throwable) {
reduce { it.copy(isLoading = false, errorMessage = t.message ?: "Fehler beim Laden") }
}
}
}
private fun save() {
val cur = _state.value
reduce { it.copy(isLoading = true, errorMessage = null) }
scope.launch {
try {
repo.save(id, cur)
reduce { it.copy(isLoading = false, dirty = false) }
} catch (t: Throwable) {
reduce { it.copy(isLoading = false, errorMessage = t.message ?: "Fehler beim Speichern") }
}
}
}
private inline fun edit(block: (PferdProfilState) -> PferdProfilState) {
reduce { block(it).copy(dirty = true) }
}
private inline fun reduce(block: (PferdProfilState) -> PferdProfilState) {
_state.value = block(_state.value)
}
}