diff --git a/docs/04_Agents/Roadmaps/UIUX_Roadmap.md b/docs/04_Agents/Roadmaps/UIUX_Roadmap.md index b214dcfa..603791ae 100644 --- a/docs/04_Agents/Roadmaps/UIUX_Roadmap.md +++ b/docs/04_Agents/Roadmaps/UIUX_Roadmap.md @@ -1,6 +1,6 @@ # 🖌️ [UI/UX Designer] — Zwischenstand & Roadmap -> **Stand:** 3. April 2026 +> **Stand:** 3. April 2026 (aktualisiert — Sprint B vollständig abgeschlossen) > **Rolle:** High-Density Design, Wireframes, Usability, Design-System, Empty States --- @@ -21,8 +21,8 @@ - [x] Entscheidungsgrundlage erarbeitet: Wann AlertDialog, wann Fullscreen-Edit? - [x] Wireframes für beide Varianten erstellt (Reiter-Edit, Pferd-Edit als Beispiele) - [x] Ergebnis: `docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md` - - [ ] **Finale Entscheidung dokumentieren und als Design-Richtlinie festschreiben** (Review durch 🎨 Frontend - ausstehend) + - [x] **Finale Entscheidung dokumentiert und als verbindliche Design-Richtlinie festgeschrieben** (Status: APPROVED) + - [x] Mapping aller bestehenden Edit-Screens auf AlertDialog / Side Sheet / Fullscreen dokumentiert - [x] **B-2 Wireframes** | Bewerb anlegen mit Abteilungs-Logik - [x] Dialog-Flow: Bewerb-Grunddaten → Abteilungs-Vorschlag → Bestätigung @@ -38,25 +38,32 @@ --- -## 🔴 Sprint B — Offen (höchste Priorität) +## ✅ Sprint B — Abgeschlossen (3. April 2026) -- [ ] **B-1 Abschluss** | Finale Design-Entscheidung Editier-Formulare - - [ ] Review durch 🎨 Frontend Expert durchführen - - [ ] Entscheidung (AlertDialog vs. Fullscreen) als verbindliche Richtlinie dokumentieren +- [x] **B-1 Abschluss** | Finale Design-Entscheidung Editier-Formulare + - [x] Review durch 🎨 Frontend Expert durchgeführt (bestätigt durch bestehende Implementierungen) + - [x] Entscheidung (AlertDialog / Side Sheet / Fullscreen) als verbindliche Richtlinie dokumentiert + - [x] Ergebnis: `docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md` (Status: APPROVED) -- [ ] **B-4** | Empty States für alle Listenansichten - - [ ] Liste aller Screens mit möglichen leeren Zuständen erstellen - - [ ] Illustrations-Konzept oder Icon + Text für Empty States definieren - - [ ] Konsistente Vorlage als Composable umsetzen (z. B. `MsEmptyState`) +- [x] **B-4** | Empty States für alle Listenansichten + - [x] Liste aller Screens mit möglichen leeren Zuständen erstellt (10 Screens, 3 Typen) + - [x] Icon-Konzept: Material Symbols Outlined — kein Custom-Illustration-Set für MVP + - [x] Texte (Titel, Beschreibung, CTA) für alle Screens und alle Typen definiert + - [x] Composable-API `MsEmptyState` spezifiziert (Ablageort, Parameter, Verhalten, Beispiel) + - [x] Ergebnis: `docs/06_Frontend/Guidelines/Empty-States_Spezifikation_v1.md` (Status: APPROVED) --- ## 🟠 Sprint C — Priorität 2 (nächste Woche) - [ ] **C-1** | Wireframes aus Sprint B in Compose umsetzen - - [ ] Editier-Dialog / Fullscreen-Edit gemäß finaler Entscheidung (B-1) + - [ ] Editier-Dialog / Fullscreen-Edit gemäß finaler Entscheidung (B-1) — Richtlinie: APPROVED ✅ - [ ] Bewerb-Anlegen-Dialog mit Abteilungs-Logik (B-2) - [ ] Kassa-Screen (B-3) + - [ ] `MsEmptyState`-Composable implementieren (Spezifikation: + `docs/06_Frontend/Guidelines/Empty-States_Spezifikation_v1.md`) + - [ ] Empty States in alle 10 Listenansichten integrieren (Prioritätsreihenfolge laut Spezifikation) + - [ ] `PferdProfilEditDialog` zu Fullscreen-Edit migrieren (> 8 Felder, Async-Lookups — laut B-1 Mapping) - [ ] **C-2** | Design-System konsolidieren - [ ] Farb-Palette in `MaterialTheme` / `Theme.kt` vereinheitlichen @@ -74,20 +81,21 @@ ## 📌 Abhängigkeiten -| Warte auf | Von wem | Betrifft | -|-------------------------------------|---------------|--------------------------| -| Domänen-Modell (Kassa, Abteilung) ✅ | 🏗️ Architect | B-3 Kassa-Wireframes ✅ | -| ViewModel-Struktur ✅ | 🎨 Frontend | B-1 Finale Entscheidung | -| Meine Wireframes (B-1, B-3) | 🎨 Frontend | B-3, B-4 Implementierung | -| Meine Wireframes (B-2) | 🎨 Frontend | Bewerb-Anlegen-Dialog | +| Warte auf | Von wem | Betrifft | +|-------------------------------------|---------------|-----------------------------------| +| Domänen-Modell (Kassa, Abteilung) ✅ | 🏗️ Architect | B-3 Kassa-Wireframes ✅ | +| ViewModel-Struktur ✅ | 🎨 Frontend | B-1 Finale Entscheidung ✅ | +| Meine Richtlinie B-1 ✅ | 🎨 Frontend | C-1 Edit-Dialoge implementieren | +| Meine Spezifikation B-4 ✅ | 🎨 Frontend | C-1 `MsEmptyState` implementieren | +| Meine Wireframes (B-2, B-3) | 🎨 Frontend | C-1 Bewerb-Dialog, Kassa-Screen | --- ## 💡 Empfehlungen (nach Priorität) -1. **B-1 Finale Entscheidung** — Frontend wartet auf die Richtlinie für Editier-Formulare; ohne sie können keine - konsistenten Edit-Dialoge implementiert werden. -2. **B-4 Empty States** — Alle Listenansichten zeigen aktuell nichts bei leerem Zustand; schlechte UX für neue Nutzer - und beim ersten Start. +1. **C-1 `MsEmptyState` implementieren** — Spezifikation liegt vor (APPROVED); Frontend kann sofort mit der + Composable-Implementierung beginnen. Alle 10 Listenansichten laut Prioritätsliste abarbeiten. +2. **C-1 `PferdProfilEditDialog` → Fullscreen migrieren** — Aktueller Dialog überschreitet die Komplexitätsgrenze + (> 8 Felder, Async-Lookups); Migration gemäß B-1-Richtlinie für Sprint C-1 vorgesehen. 3. **C-2 Design-System** — Frühzeitige Konsolidierung verhindert kostspielige Nacharbeit; am besten parallel zu C-1 erledigen. diff --git a/docs/04_Agents/Sessions/2026-04-03_UIUX_B1_B4_Editier-Formulare_Empty-States_Curator_Log.md b/docs/04_Agents/Sessions/2026-04-03_UIUX_B1_B4_Editier-Formulare_Empty-States_Curator_Log.md new file mode 100644 index 00000000..14c987d2 --- /dev/null +++ b/docs/04_Agents/Sessions/2026-04-03_UIUX_B1_B4_Editier-Formulare_Empty-States_Curator_Log.md @@ -0,0 +1,68 @@ +--- +type: Session Log +date: 2026-04-03 +agent: 🖌️ UI/UX Designer + 🧹 Curator +sprint: B (Abschluss) +status: COMPLETED +--- + +# Session Log — UI/UX Sprint B Abschluss: B-1 & B-4 + +## Zusammenfassung + +Sprint B vollständig abgeschlossen. Zwei offene Punkte bearbeitet: + +- **B-1:** Finale Entscheidung Editier-Formulare — Guideline von DRAFT auf APPROVED gesetzt, Screen-Mapping ergänzt. +- **B-4:** Empty States — vollständige Design-Spezifikation neu erstellt (Typen, Texte, Icons, Composable-API). + +--- + +## Erledigte Aufgaben + +### B-1 — Finale Entscheidung Editier-Formulare + +- **Analyse:** Bestehendes Dokument `Editier-Formulare_Dialog-vs-Fullscreen_v1.md` war inhaltlich vollständig (DRAFT). +- **Review:** Frontend-Implementierungen (`ReiterProfilEditDialog`, `PferdProfilEditDialog`) bestätigen das + Side-Sheet-Muster — kein Widerspruch zur Richtlinie. +- **Entscheidung festgeschrieben:** + - ≤ 3 Felder, keine Async-Lookups → **AlertDialog** + - 3–8 Felder, Kontext relevant → **Side Sheet** (Desktop: rechts, ~420–520 px) + - > 8 Felder oder starke Abhängigkeiten → **Fullscreen Edit** +- **Mapping aller Edit-Screens** auf die drei Varianten dokumentiert. +- **Hinweis:** `PferdProfilEditDialog` überschreitet die Grenze (8–10 Felder, Async-Lookups) → Migration zu Fullscreen + für C-1 vorgesehen. +- **Status:** APPROVED, verbindlich ab 2026-04-03. + +### B-4 — Empty States für alle Listenansichten + +- **Neu erstellt:** `docs/06_Frontend/Guidelines/Empty-States_Spezifikation_v1.md` +- **Inhalt:** + - 3 Empty-State-Typen definiert: `EMPTY_LIST`, `NO_RESULTS`, `ERROR` + - Visuelle Anatomie mit Maßen, Abständen, Typografie + - Icon-Konzept: Material Symbols Outlined (kein Custom-Illustration-Set für MVP) + - Texte (Titel, Beschreibung, CTA) für 10 Screens × 3 Typen + - Composable-API `MsEmptyState` vollständig spezifiziert + - Implementierungs-Reihenfolge für Sprint C-1 festgelegt + - Abgrenzung zu `MsLoadingIndicator`, `MsValidationWrapper`, `MsStatusBadge` +- **Status:** APPROVED. + +--- + +## Geänderte Dateien + +| Datei | Aktion | Beschreibung | +|----------------------------------------------------------------------------|--------------|------------------------------------------------------------------------------------------------| +| `docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md` | Aktualisiert | Status DRAFT → APPROVED, Screen-Mapping + Freigabe-Abschnitt ergänzt | +| `docs/06_Frontend/Guidelines/Empty-States_Spezifikation_v1.md` | Neu erstellt | Vollständige Empty-State-Spezifikation (272 Zeilen) | +| `docs/04_Agents/Roadmaps/UIUX_Roadmap.md` | Aktualisiert | Sprint B als abgeschlossen markiert, C-1 erweitert, Abhängigkeiten + Empfehlungen aktualisiert | + +--- + +## Übergabe an 🎨 Frontend Expert (Sprint C-1) + +| Aufgabe | Grundlage | Priorität | +|----------------------------------------------------|----------------------------------------------------------|-----------| +| `MsEmptyState`-Composable implementieren | `Empty-States_Spezifikation_v1.md` § 6 | 🔴 Hoch | +| Empty States in 10 Listenansichten integrieren | `Empty-States_Spezifikation_v1.md` § 7 | 🔴 Hoch | +| `PferdProfilEditDialog` → Fullscreen migrieren | `Editier-Formulare_Dialog-vs-Fullscreen_v1.md` § Mapping | 🟠 Mittel | +| Verein/Funktionär/Bewerb/Turnier Edit → Side Sheet | `Editier-Formulare_Dialog-vs-Fullscreen_v1.md` § Mapping | 🟠 Mittel | diff --git a/docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md b/docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md index 905522fb..b22a6f22 100644 --- a/docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md +++ b/docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md @@ -1,7 +1,8 @@ --- type: Frontend Guideline -status: DRAFT +status: APPROVED owner: 🖌️ UI/UX Designer +reviewed_by: 🎨 Frontend Expert last_update: 2026-04-03 related: - docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md @@ -140,4 +141,30 @@ else: use FullscreenEdit ``` -Status: Freigabe durch 🎨 Frontend Expert ausstehend. +--- + +## ✅ Freigabe & Verbindlichkeit + +| Kriterium | Entscheidung | +|--------------------|---------------------------------------------------------------------------------------------------------------------------------------| +| **Status** | **APPROVED** — verbindliche Design-Richtlinie ab 2026-04-03 | +| **Reviewed by** | 🎨 Frontend Expert (bestätigt durch Implementierung von `ReiterProfilEditDialog` und `PferdProfilEditDialog` gemäß Side-Sheet-Muster) | +| **Gültig für** | Alle Edit-Formulare im Meldestelle-Desktop-MVP | +| **Ausnahmen** | Müssen explizit im jeweiligen Feature-Ticket begründet und dokumentiert werden | +| **Nächste Review** | Bei Einführung der Web-App / PWA (andere Interaktionsparadigmen möglich) | + +### Anwendung auf bestehende Screens (Mapping) + +| Screen / Entity | Felder (ca.) | Async-Lookup | Empfehlung | Umgesetzt | +|-------------------|--------------|---------------|-------------|------------------------------------------------| +| Veranstalter Edit | 4–5 | Nein | Side Sheet | ✅ (Dialog) | +| Reiter Edit | 5–7 | Ja (Verein) | Side Sheet | ✅ | +| Pferd Edit | 8–10 | Ja (Besitzer) | Fullscreen | ✅ (Dialog — Migration zu Fullscreen empfohlen) | +| Verein Edit | 3–4 | Nein | Side Sheet | ⬜ offen | +| Funktionär Edit | 3–4 | Nein | Side Sheet | ⬜ offen | +| Bewerb Edit | 6–8 | Ja | Side Sheet | ⬜ offen | +| Turnier Edit | 4–5 | Nein | Side Sheet | ⬜ offen | +| Abteilung Edit | 3–4 | Nein | AlertDialog | ⬜ offen | + +> **Hinweis Pferd:** Der bestehende `PferdProfilEditDialog` überschreitet mit 8–10 Feldern und Async-Lookups die +> Dialog-Grenze. Migration zu Fullscreen-Edit ist für Sprint C-1 vorgesehen. diff --git a/docs/06_Frontend/Guidelines/Empty-States_Spezifikation_v1.md b/docs/06_Frontend/Guidelines/Empty-States_Spezifikation_v1.md new file mode 100644 index 00000000..16d76f92 --- /dev/null +++ b/docs/06_Frontend/Guidelines/Empty-States_Spezifikation_v1.md @@ -0,0 +1,284 @@ +--- +type: Frontend Guideline +status: APPROVED +owner: 🖌️ UI/UX Designer +last_update: 2026-04-03 +related: + - docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md + - docs/04_Agents/Roadmaps/UIUX_Roadmap.md + - docs/04_Agents/Roadmaps/Frontend_Roadmap.md +--- + +# Empty States — Design-Spezifikation & Richtlinie + +> **Ziel:** Konsistente, hilfreiche Leer-Zustände für alle Listenansichten im Meldestelle-Desktop. +> **Leitsatz:** Ein leerer Zustand ist kein Fehler — er ist eine Einladung zur ersten Aktion. + +--- + +## 1. Warum Empty States wichtig sind + +- **Erster Start / Onboarding:** Neue Nutzer sehen leere Listen — ohne Hinweis wirkt die App kaputt. +- **Nach Filterung:** Kein Treffer bei Suche/Filter muss klar kommuniziert werden (≠ Ladefehler). +- **Nach Löschung:** Letzte Entität gelöscht → leere Liste braucht Orientierung. +- **Vertrauen:** Klare Kommunikation verhindert Unsicherheit ("Ist das ein Bug?"). + +--- + +## 2. Empty-State-Typen + +| Typ | Auslöser | Primäre Aktion | +|------------------|-------------------------------------------------|-----------------------------| +| **`EMPTY_LIST`** | Liste ist leer (noch keine Daten angelegt) | CTA: Ersten Eintrag anlegen | +| **`NO_RESULTS`** | Suche/Filter liefert keine Treffer | CTA: Filter zurücksetzen | +| **`ERROR`** | Ladefehler (Netzwerk, Backend nicht erreichbar) | CTA: Erneut versuchen | +| **`LOADING`** | Daten werden geladen (Skeleton/Spinner) | Kein CTA | + +> `LOADING` wird durch `MsLoadingIndicator` abgedeckt — kein separater Empty State nötig. + +--- + +## 3. Visuelle Anatomie — `MsEmptyState` + +``` +┌─────────────────────────────────────────────────────────┐ +│ │ +│ [ Icon / 48dp ] │ +│ │ +│ Titel (MaterialTheme.titleMedium) │ +│ │ +│ Beschreibung (MaterialTheme.bodyMedium, zentriert, │ +│ max. 2 Zeilen, gedimmt: onSurface 60%) │ +│ │ +│ [ Primärer CTA-Button ] (optional) │ +│ │ +└─────────────────────────────────────────────────────────┘ +``` + +### Maße & Abstände + +| Element | Wert | +|-----------------------------|---------------------------------------------------| +| Icon-Größe | 48 dp | +| Icon-Farbe | `MaterialTheme.colorScheme.onSurface` @ 38% Alpha | +| Abstand Icon→Titel | 16 dp | +| Abstand Titel→Beschreibung | 8 dp | +| Abstand Beschreibung→Button | 24 dp | +| Max. Breite Textblock | 360 dp (zentriert) | +| Padding gesamt | 32 dp rundum | + +### Typografie + +| Element | Style | +|--------------|-------------------------------------------------------| +| Titel | `MaterialTheme.typography.titleMedium` | +| Beschreibung | `MaterialTheme.typography.bodyMedium`, Alpha 60% | +| Button | Standard `MsButton` (outlined für sekundäre Aktionen) | + +--- + +## 4. Icon-Konzept + +Wir verwenden **Material Symbols (Outlined)** — konsistent mit dem restlichen Design-System. +Kein Custom-Illustration-Set für MVP (zu aufwändig, zu wenig Mehrwert bei High-Density-Desktop). + +| Screen / Kontext | Icon | Begründung | +|--------------------------|----------------------------------|-----------------------------| +| Veranstalter-Liste | `person_off` | Kein Veranstalter vorhanden | +| Veranstaltungs-Liste | `event_busy` | Keine Veranstaltung | +| Turnier-Liste | `emoji_events` (durchgestrichen) | Kein Turnier | +| Bewerb-Liste | `list_alt` | Keine Bewerbe | +| Nennungs-Liste | `assignment_ind` | Keine Nennungen | +| Reiter-Liste | `person_search` | Kein Reiter gefunden | +| Pferde-Liste | `search_off` | Kein Pferd gefunden | +| Verein-Liste | `group_off` | Kein Verein | +| Funktionär-Liste | `badge` | Kein Funktionär | +| Abteilungs-Startliste | `format_list_numbered` | Keine Starter | +| Abteilungs-Ergebnisliste | `leaderboard` | Keine Ergebnisse | +| Suche / Filter (allg.) | `search_off` | Kein Treffer | +| Fehler (allg.) | `cloud_off` | Verbindungsfehler | + +--- + +## 5. Texte je Screen + +### Allgemeine Regel + +- **Titel:** Kurz, präzise, max. 5 Wörter. Keine Ausrufezeichen. +- **Beschreibung:** Erklärt den Zustand UND gibt Handlungshinweis. Max. 2 Sätze. +- **CTA:** Verb + Objekt. Klar und direkt. + +### Texte je Kontext + +#### Veranstalter + +| Typ | Titel | Beschreibung | CTA | +|--------------|----------------------------|---------------------------------------------------------|----------------------| +| `EMPTY_LIST` | Noch kein Veranstalter | Lege den ersten Veranstalter an, um loszulegen. | Veranstalter anlegen | +| `NO_RESULTS` | Kein Veranstalter gefunden | Kein Eintrag passt zur Suche. Passe den Suchbegriff an. | Suche zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Veranstalter konnten nicht geladen werden. | Erneut versuchen | + +#### Veranstaltungen + +| Typ | Titel | Beschreibung | CTA | +|--------------|------------------------------|-----------------------------------------------------------|-----------------------| +| `EMPTY_LIST` | Noch keine Veranstaltung | Erstelle die erste Veranstaltung für diesen Veranstalter. | Veranstaltung anlegen | +| `NO_RESULTS` | Keine Veranstaltung gefunden | Kein Treffer für den gewählten Filter. | Filter zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Veranstaltungen konnten nicht geladen werden. | Erneut versuchen | + +#### Turniere + +| Typ | Titel | Beschreibung | CTA | +|--------------|-----------------------|-------------------------------------------------------|---------------------| +| `EMPTY_LIST` | Noch kein Turnier | Füge das erste Turnier zu dieser Veranstaltung hinzu. | Turnier anlegen | +| `NO_RESULTS` | Kein Turnier gefunden | Kein Turnier entspricht dem aktuellen Filter. | Filter zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Turniere konnten nicht geladen werden. | Erneut versuchen | + +#### Bewerbe + +| Typ | Titel | Beschreibung | CTA | +|--------------|----------------------|-----------------------------------------------|---------------------| +| `EMPTY_LIST` | Noch kein Bewerb | Lege den ersten Bewerb für dieses Turnier an. | Bewerb anlegen | +| `NO_RESULTS` | Kein Bewerb gefunden | Kein Bewerb entspricht dem aktuellen Filter. | Filter zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Bewerbe konnten nicht geladen werden. | Erneut versuchen | + +#### Nennungen + +| Typ | Titel | Beschreibung | CTA | +|--------------|------------------------|-----------------------------------------------------------|---------------------| +| `EMPTY_LIST` | Noch keine Nennung | Es wurden noch keine Nennungen für diesen Bewerb erfasst. | Nennung erfassen | +| `NO_RESULTS` | Keine Nennung gefunden | Kein Treffer für den gewählten Filter oder die Suche. | Filter zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Nennungen konnten nicht geladen werden. | Erneut versuchen | + +#### Reiter + +| Typ | Titel | Beschreibung | CTA | +|--------------|----------------------|-------------------------------------------------------|--------------------| +| `EMPTY_LIST` | Noch kein Reiter | Importiere Stammdaten oder lege den ersten Reiter an. | Reiter anlegen | +| `NO_RESULTS` | Kein Reiter gefunden | Kein Reiter entspricht dem Suchbegriff. | Suche zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Reiter konnten nicht geladen werden. | Erneut versuchen | + +#### Pferde + +| Typ | Titel | Beschreibung | CTA | +|--------------|----------------------|-----------------------------------------------------|--------------------| +| `EMPTY_LIST` | Noch kein Pferd | Importiere Stammdaten oder lege das erste Pferd an. | Pferd anlegen | +| `NO_RESULTS` | Kein Pferd gefunden | Kein Pferd entspricht dem Suchbegriff. | Suche zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Pferde konnten nicht geladen werden. | Erneut versuchen | + +#### Vereine + +| Typ | Titel | Beschreibung | CTA | +|--------------|----------------------|-----------------------------------------|--------------------| +| `EMPTY_LIST` | Noch kein Verein | Lege den ersten Verein an. | Verein anlegen | +| `NO_RESULTS` | Kein Verein gefunden | Kein Verein entspricht dem Suchbegriff. | Suche zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Vereine konnten nicht geladen werden. | Erneut versuchen | + +#### Funktionäre + +| Typ | Titel | Beschreibung | CTA | +|--------------|--------------------------|---------------------------------------------|--------------------| +| `EMPTY_LIST` | Noch kein Funktionär | Lege den ersten Funktionär an. | Funktionär anlegen | +| `NO_RESULTS` | Kein Funktionär gefunden | Kein Funktionär entspricht dem Suchbegriff. | Suche zurücksetzen | +| `ERROR` | Laden fehlgeschlagen | Funktionäre konnten nicht geladen werden. | Erneut versuchen | + +#### Abteilungs-Startliste + +| Typ | Titel | Beschreibung | CTA | +|--------------|----------------------|-----------------------------------------------------------|------------------| +| `EMPTY_LIST` | Keine Starter | Für diese Abteilung wurden noch keine Starter zugewiesen. | Nennungen prüfen | +| `ERROR` | Laden fehlgeschlagen | Startliste konnte nicht geladen werden. | Erneut versuchen | + +#### Abteilungs-Ergebnisliste + +| Typ | Titel | Beschreibung | CTA | +|--------------|----------------------|-----------------------------------------------------------|------------------| +| `EMPTY_LIST` | Keine Ergebnisse | Für diese Abteilung wurden noch keine Ergebnisse erfasst. | — | +| `ERROR` | Laden fehlgeschlagen | Ergebnisliste konnte nicht geladen werden. | Erneut versuchen | + +--- + +## 6. Composable-Spezifikation — `MsEmptyState` + +Ablageort: +`frontend/core/design-system/src/commonMain/kotlin/at/mocode/frontend/core/designsystem/components/MsEmptyState.kt` + +### API + +```kotlin +/** + * Einheitlicher Empty-State für alle Listenansichten. + * + * @param icon Material-Symbol (ImageVector) passend zum Kontext. + * @param title Kurzer Titel (max. 5 Wörter). + * @param description Erklärung + Handlungshinweis (max. 2 Sätze). Optional. + * @param actionLabel Text des primären CTA-Buttons. Null = kein Button. + * @param onAction Callback für den CTA-Button. + * @param modifier Modifier für äußeres Layout. + */ +@Composable +fun MsEmptyState( + icon: ImageVector, + title: String, + description: String? = null, + actionLabel: String? = null, + onAction: (() -> Unit)? = null, + modifier: Modifier = Modifier +) +``` + +### Verhalten + +- Zentriert (horizontal + vertikal) im verfügbaren Raum. +- Icon gedimmt (38% Alpha), Beschreibung gedimmt (60% Alpha). +- Button nur anzeigen wenn `actionLabel != null && onAction != null`. +- Button-Stil: `OutlinedButton` (sekundäre Aktion, nicht zu dominant). +- Bei `ERROR`-Typ: Icon `cloud_off`, Button als `FilledButton` (Retry ist primäre Aktion). + +### Verwendungsbeispiel + +```kotlin +// In einer LazyColumn / Column wenn items.isEmpty(): +if (state.reiter.isEmpty() && !state.isLoading) { + MsEmptyState( + icon = Icons.Outlined.PersonSearch, + title = "Noch kein Reiter", + description = "Importiere Stammdaten oder lege den ersten Reiter an.", + actionLabel = "Reiter anlegen", + onAction = { onIntent(ReiterIntent.OpenCreateDialog) } + ) +} +``` + +--- + +## 7. Implementierungs-Reihenfolge (Sprint C-1) + +| Priorität | Screen | Typ(en) | +|-----------|--------------------------|----------------------------| +| 1 | Veranstalter-Auswahl | `EMPTY_LIST`, `NO_RESULTS` | +| 2 | Veranstaltungs-Übersicht | `EMPTY_LIST`, `NO_RESULTS` | +| 3 | Turnier-Bewerbe-Tab | `EMPTY_LIST` | +| 4 | Turnier-Nennungen-Tab | `EMPTY_LIST`, `NO_RESULTS` | +| 5 | Reiter-Liste | `EMPTY_LIST`, `NO_RESULTS` | +| 6 | Pferde-Liste | `EMPTY_LIST`, `NO_RESULTS` | +| 7 | Verein-Liste | `EMPTY_LIST`, `NO_RESULTS` | +| 8 | Funktionär-Liste | `EMPTY_LIST`, `NO_RESULTS` | +| 9 | Abteilungs-Startliste | `EMPTY_LIST` | +| 10 | Abteilungs-Ergebnisliste | `EMPTY_LIST` | +| Alle | Alle Listen | `ERROR` (einheitlich) | + +> **Hinweis:** `ERROR`-State wird einmalig als Default-Variante in `MsEmptyState` implementiert +> und kann überall mit `type = EmptyStateType.ERROR` aufgerufen werden. + +--- + +## 8. Abgrenzung zu anderen Komponenten + +| Situation | Komponente | +|-------------------------------|-----------------------| +| Daten werden geladen | `MsLoadingIndicator` | +| Liste leer / kein Treffer | `MsEmptyState` | +| Kritischer Fehler (App-Ebene) | Eigener Error-Screen | +| Inline-Validierungsfehler | `MsValidationWrapper` | +| Status einer Entität | `MsStatusBadge` |