# Matrix / Element Feature Checklist für Pyramid *Stand: April 2026 — Pyramid v0.1.x (Early Development)* *Letzte Tiefenanalyse: 2026-04-29 (Vergleich mit FluffyChat / Element Web)* --- ## Legende - ✅ `[x]` — Implementiert und funktioniert korrekt - ⚠️ `[~]` — Teilweise / fehlerhaft implementiert (Details in Technische Analyse) - ❌ `[ ]` — Fehlt komplett - 🔴 P0 — Kritisch (Kernfunktionalität kaputt) - 🟠 P1 — Hoch (wichtige Funktion defekt oder nicht vorhanden) - 🟡 P2 — Mittel - 🔵 P3 — Niedrig / Nice-to-have --- ## Nachrichten (Messaging) ### Kern-Funktionen - [x] Textnachrichten senden - [x] Nachrichten empfangen & anzeigen - [x] Zeitstempel (formatiert, relativ) - [x] Nachrichtengruppierung (gleicher Sender, <5 Min.) - [x] Datumstrennlinien zwischen Gruppen - [x] Verschlüsselte Nachrichten anzeigen (Entschlüsselungsstatus) - [x] Nachrichtenverlauf paginieren (ältere Nachrichten beim Scrollen laden) - [x] Ungelesene-Nachrichten-Tracking - [~] Nachrichtenbearbeitung (Edit-Event erkannt, `getDisplayEvent` wird nicht gerendert) 🟠 P1 - [~] Nachrichtenvorschau bei Reply (Zitat-Preview vorhanden, kein Jump-to-original) 🟡 P2 ### Nachrichtenaktionen - [x] Nachrichtentext kopieren - [x] Eigene Nachrichten löschen (redact) - [x] Nachrichten anpinnen / Pinboard anzeigen - [x] Auf Nachrichten antworten (in-reply-to) - [ ] Nachrichten weiterleiten - [ ] Zitat-Styling (visuelle Blockquote-Anzeige) ### Textformatierung (formatted_body) - [~] Markdown-Rendering — `formatted_body` / `org.matrix.custom.html` wird nicht gesendet und nicht gerendert 🔵 P3 - [ ] Fett (**text**) - [ ] Kursiv (*text*) - [ ] Durchgestrichen (~~text~~) - [ ] Inline-Code (`code`) - [ ] Code-Block (```code```) - [ ] Aufzählungslisten - [ ] Klickbare Links - [~] @Erwähnungen — Button vorhanden, `onTap: null` 🟡 P2 - [ ] #Kanal-Erwähnungen - [ ] Spoiler-Tags (||text||) ### Medien & Anhänge - [x] Dateianhänge senden (mit MIME-Erkennung) - [x] Bilder senden & inline anzeigen - [x] Videos senden & inline abspielen - [x] Audio senden & inline abspielen - [x] Sticker anzeigen (m.sticker) - [x] Dateianhang mit Untertitel - [x] Dateigröße berechnen & anzeigen - [x] Verschlüsselte Medien entschlüsseln & herunterladen - [x] Thumbnail-Generierung für Bilder/Videos - [~] Sprachnachrichten (Struktur vorhanden, Wiedergabe-UI fehlt) - [ ] Animierte GIFs - [ ] Link-Vorschau (URL-Unfurling) - [ ] Dokument-Vorschau (PDF, Office) ### Reaktionen - [x] Emoji-Reaktionen senden - [x] Reaktionszähler anzeigen - [x] 6 häufigste Reaktionen als Schnellauswahl - [x] Vollständiger Emoji-Picker mit Suche - [x] Eigene Reaktion entfernen - [x] Anzeigen wer reagiert hat - [x] Mehrere Reaktionen pro Nachricht - [x] Kategoriebasierte Emoji-Organisation ### Tipp-Indikatoren (Typing) - [~] `room.setTyping()` wird **nirgendwo aufgerufen** — Einstellung existiert, aber Composer sendet nie "tippt…" 🟡 P2 - [ ] "X tippt gerade"-Anzeige empfangen (kein Widget) - [ ] Timeout nach Tipp-Ende ### Threads - [~] Thread-Button vorhanden (`onPressed: () {}` — leer) 🔵 P3 - [ ] Thread aufklappen / eigene Ansicht - [ ] Thread-Benachrichtigungen - [ ] Thread als gelöst markieren --- ## Lesebestätigungen (Read Receipts) - [x] Senden von `m.read`-Receipts via `room.setReadMarker()` - [x] Privacy-Toggle (kein Senden wenn deaktiviert) - [x] ✓-Icon (Nachricht gesendet/zugestellt) auf eigenen Nachrichten - [x] ✓✓-Icon (gelesen) in DMs - [x] Sende-Status (Uhr/Fehler/gesendet/gelesen) - [~] ✓✓-Logik nur für DMs — in Gruppenräumen wird `receiptState.global.otherUsers` nicht ausgewertet 🟡 P2 - [~] **Off-by-one**: Divider erscheint *über* der Gruppe die das `fullyRead`-Event enthält, nicht darunter 🟡 P2 - [ ] Gruppen-Read-Receipt-Display (Seen-by-Avatare wie in FluffyChat) 🟡 P2 - [ ] Hover-Tooltip "Gelesen von: ..." auf ✓✓ - [ ] **Notification-Cancellation**: `cancelNotification(roomId)` beim Setzen des Read-Markers 🟡 P2 --- ## „Neue Nachrichten" Trennlinie - [x] `_UnreadDivider`-Widget korrekt gestylt - [x] `_sessionFullyReadId` einmalig beim Öffnen erfasst (stabil für die Session) - [x] Keine Anzeige wenn Raum bereits gelesen - [~] **Position falsch** — Divider über der Gruppe mit `fullyRead`-Event statt darunter 🟡 P2 - [ ] **Auto-Scroll zum Divider** beim Öffnen eines Raums mit ungelesenen Nachrichten 🟡 P2 --- ## Presence / Zuletzt Online - [x] `_PresenceLine` im DM-Header mit Live-Updates - [x] 4s-Debounce gegen Sync-Spike-Fehlmeldungen - [x] Relative Zeitanzeige (gerade eben / vor Xmin / vor Xh) - [x] Guard: eigene Presence wird nie angezeigt - [x] Presence-Dot im Rooms-Panel und Members-Panel - [x] `setPresence(online/offline)` in den Settings - [~] **Kein Auto-Heartbeat** — `setPresence` nur in Settings, nie periodisch während Nutzung 🔵 P3 - [~] **Kein `WidgetsBindingObserver`** — App-Lifecycle (Hintergrund/Vordergrund) löst kein Presence-Event aus 🔵 P3 - [ ] Presence-Dot in DM-Listen-Items (`room_list_item.dart`) 🔵 P3 --- ## Benachrichtigungen ### Local Notifications (App im Vordergrund) - [x] Android Local Notifications (`flutter_local_notifications`) - [x] Windows Toast-Notifications (`local_notifier`) - [x] Windows Taskbar-Badge (Progress-Error-Mode) - [x] Tap-Handler navigiert zum richtigen Raum (Android) - [x] Guards: nur fremde Nachrichten, nur aktive Rooms, nur `Membership.join` - [x] `notificationsBlockedProvider` + Banner in `app_shell.dart` - [~] **Alle 4 Notification-Prefs werden ignoriert** — `notifDesktopProvider`, `notifSoundProvider`, `notifPreviewProvider`, `notifMentionOnlyDmProvider` haben keinen Effekt 🟠 P1 - [~] Android-Grouping ohne Summary-Notification 🔵 P3 ### Remote Push (App im Hintergrund / geschlossen) - [ ] 🔴 **Keine Remote-Push-Integration** — FCM/UnifiedPush fehlt komplett, App muss laufen - [ ] iOS APNs-Setup - [ ] macOS-Notifications - [ ] Android Icon-Badge (Zahlenbadge) --- ## E2EE Verschlüsselungs-Pipeline ### Implementiert - [x] Vodozemac (Rust-Olm) via Flutter-Isolate — modern, performant - [x] Bootstrap: SSSS, Cross-Signing, Online-Key-Backup - [x] `_decryptLegacyEvents` — entschlüsselt ältere Events in-place - [x] Device-Key-Preload vor erstem Senden - [x] Key-Verification UI (SAS Emoji, QR-Code, alle States) - [x] Megolm Session Export/Import (Element-kompatibles Format) - [x] Encrypted-Attachment-Handling - [x] `m.fully_read`-Marker beim Timeline-Open - [x] `timeline.requestKeys(onlineKeyBackupOnly: false)` ### Fehlerhaft / Fehlend - [~] **"Entschlüsselt…"-Placeholder bleibt dauerhaft** wenn Key fehlt — kein Recovery-Button 🟠 P1 - [~] `loadAllKeysFromRoom` Fehler werden silent geschluckt (`catch (_) {}`) 🟡 P2 - [~] **Kein Incoming-Verification-Request-Handler** — `client.onKeyVerificationRequest` wird nicht abonniert 🔴 P0 - [~] **Doppelte Bootstrap-Implementierung** (page vs. dialog) mit leicht inkonsistenter Logik 🔵 P3 - [ ] Device-Trust-Indicator in der Timeline 🔵 P3 - [ ] Unverified-Device-Warning beim Senden 🔵 P3 - [ ] "Schlüssel anfordern"-Button bei dauerhaft verschlüsselten Events 🟠 P1 --- ## Suche - [x] Suchdialog öffnen (UI vorhanden) - [x] Server-seitige Volltextsuche via Matrix `/search` API - [x] Filter: Alle / Medien / Personen - [x] Ergebnisse: Raum + Absender + Body + Zeitstempel - [x] Keyboard-Navigation in Ergebnissen - [x] 400ms Debounce - [ ] Jump-to-Message bei Klick auf Suchergebnis - [ ] Suche nach Absender filtern - [ ] Filter nach Datum - [ ] Suchergebnisse im Chat hervorheben - [ ] Suchverlauf --- ## Raumverwaltung ### Grundfunktionen - [x] Raumliste anzeigen (sortiert nach letzter Aktivität) - [x] Räume beitreten - [x] Räume verlassen - [x] Raumname & Avatar anzeigen - [x] Verschlüsselungsstatus (Schloss-Icon) - [x] Einladungen annehmen / ablehnen - [ ] Neuen Raum erstellen (UI-Einstiegspunkt) - [ ] Raumname bearbeiten - [ ] Raumthema/Beschreibung bearbeiten - [ ] Raum-Avatar ändern - [ ] Raumvisibilität (öffentlich / privat) - [ ] Verlaufsvisibilität konfigurieren ### Direktnachrichten (DMs) - [x] 1:1 DM-Räume anzeigen & öffnen - [x] Presence-Status des Gegenübers anzeigen - [x] Echtzeit-Presence-Updates - [x] Sprachanruf aus DM starten - [x] Videoanruf aus DM starten - [ ] DM starten (neuen Chat beginnen) ### Mitglieder & Rollen - [x] Mitgliederliste anzeigen - [x] Mitgliederanzahl anzeigen - [x] Avatar & Anzeigename der Mitglieder - [x] Nutzer in Raum einladen - [ ] Nutzer aus Raum entfernen (Kick) - [ ] Nutzer sperren (Ban) - [ ] Power Levels bearbeiten --- ## Spaces & Gemeinschaften - [x] Spaces in der Seitenleiste anzeigen - [x] Zwischen Spaces navigieren - [x] Space-Avatar & Banner anzeigen - [x] Räume nach Space filtern - [x] Unterkategorien (Sub-Spaces) - [x] Drag-and-drop Kanalreihenfolge für Admins - [x] Space-Verwaltungsdialog - [ ] Neuen Space erstellen - [ ] Räume zum Space hinzufügen / entfernen - [ ] Space-Entdeckung (öffentliche Spaces) --- ## Sprach- & Videoanrufe (LiveKit) - [x] Sprachkanal betreten / verlassen - [x] Mikrofon stummschalten / Deafen - [x] Teilnehmerliste im Sprachkanal - [x] Anruf-UI (Vollansicht + Mini-Widget) - [x] Videoanruf mit Kamera-Toggle - [ ] Klingelton bei eingehenden Anrufen - [ ] Anruf annehmen / ablehnen (UI) - [ ] Anrufdauer-Timer - [ ] Bildschirmfreigabe --- ## Nutzereinstellungen & Profil - [x] Hell / Dunkel-Theme, Akzentfarbe, Eckradius, Dichte - [x] Eigene User-ID, Avatar (Initialen-Fallback), Anzeigename anzeigen - [ ] Anzeigenamen & Avatar bearbeiten - [ ] Passwort ändern - [ ] Sitzungsverwaltung - [ ] Konto deaktivieren --- ## Auto-Update - [x] GitHub-Releases als Update-Quelle - [x] Versions-Vergleich (SemVer), Rate-Limiting, Update-Banner - [x] "Diese Version überspringen"-Option - [ ] Automatischer Download & Installation --- ## Plattform-spezifisch ### Desktop - [x] Native Desktop-App, Tastenkürzel, Drag-and-Drop - [ ] System-Tray-Integration - [ ] Fenster-State speichern (Größe, Position) ### Mobile - [x] Mobile App (Flutter), Drawer-Navigation - [ ] Touch-optimiertes UI - [ ] Mobile Push-Benachrichtigungen --- --- # Technische Tiefenanalyse (2026-04-29) *Vergleichsbasis: FluffyChat (krille-chan/fluffychat) und Element Web* *Format: Befund → betroffene Datei:Zeile → Referenz-Implementierung* --- ## IMPLEMENTIERUNGS-BACKLOG (nach Priorität) ### 🔴 P0 — Kritisch #### [P0-1] Incoming Key-Verification-Request-Handler fehlt **Problem:** Wenn ein anderes Gerät eine Verifikations-Anfrage (`m.key.verification.request`) an Pyramid schickt, gibt es keinen Listener. Die Anfrage läuft ab, ohne dass der Nutzer sie sieht. Das bedeutet: andere Geräte können Pyramid de facto nicht verifizieren — nur Pyramid kann aktiv verifizieren. **Betroffene Datei:** `lib/widgets/settings_modal.dart` (kein `onKeyVerificationRequest`-Listener) **FluffyChat-Referenz:** `lib/pages/key_verification/key_verification_dialog.dart` + `client.onKeyVerificationRequest.stream.listen(...)` in `lib/pages/matrix.dart` **Fix:** Stream auf `client.onKeyVerificationRequest` in `matrix_client.dart` oder `app_shell.dart` subscriben und `KeyVerificationDialog` öffnen. --- ### 🟠 P1 — Hoch #### [P1-1] Notification-Prefs werden ignoriert **Problem:** `notifDesktopProvider`, `notifSoundProvider`, `notifPreviewProvider`, `notifMentionOnlyDmProvider` sind in `settings_prefs.dart` gespeichert, werden in `notification_service.dart/_watchEvents()` aber nie ausgelesen. Notifications erscheinen immer, unabhängig von Nutzereinstellungen. **Betroffene Datei:** `lib/core/notification_service.dart`, Zeile 145–168 **Fix:** In `_watchEvents()` die Prefs vor `showMessageNotification()` prüfen. #### [P1-2] Edits werden nicht gerendert **Problem:** `_isVisible()` filtert Edit-Events korrekt heraus, aber `event.getDisplayEvent(timeline)` wird nirgendwo aufgerufen. Nachrichten zeigen immer die Originalversion, auch wenn sie via `m.replace` bearbeitet wurden. Ein `(bearbeitet)`-Label fehlt ebenfalls. **Betroffene Datei:** `lib/features/chat/message_group.dart` — Event-Rendering-Bereich **FluffyChat-Referenz:** `event.getDisplayEvent(timeline)` vor dem Rendern jedes Events **Fix:** Beim Rendern von Events `event.getDisplayEvent(timeline)` statt `event` verwenden; `(bearbeitet)`-Label wenn `event != displayEvent`. #### [P1-3] Encrypted-Placeholder bleibt dauerhaft — kein Recovery-Button **Problem:** `EventTypes.Encrypted` zeigt "Nachricht wird entschlüsselt…" dauerhaft wenn die Entschlüsselung scheitert. Es gibt keinen Button zum Anfordern fehlender Keys. **Betroffene Datei:** `lib/features/chat/message_group.dart`, Zeilen ~408–421 **FluffyChat-Referenz:** `_requestMissingKey()` mit `room.client.sendToDeviceEncrypted(...)` / SDK-`requestKey()` **Fix:** Wenn `event.status == EventStatus.error` oder nach Timeout immer noch `EventTypes.Encrypted`: "Schlüssel anfordern"-Button anzeigen, der `timeline.requestKeys()` aufruft. --- ### 🟡 P2 — Mittel #### [P2-1] Typing-Indikator: `room.setTyping()` nie aufgerufen **Problem:** `privacyTypingProvider` existiert, `chat_composer.dart` ruft aber nie `room.setTyping()` auf. Andere Nutzer sehen nie "X tippt gerade…". **Betroffene Datei:** `lib/features/chat/chat_input.dart` (oder `chat_composer.dart`) **FluffyChat-Referenz:** `onInputBarChanged` → 2s Debounce → `room.setTyping(true, timeout: 30000)`; bei Senden/Leerfeld: `room.setTyping(false)` **Fix:** Im Composer-Input `onChanged`-Handler mit Debounce und `room.setTyping()` ergänzen. #### [P2-2] Typing-Indikator: Kein Display-Widget **Problem:** Kein Widget das `room.typingUsers` anzeigt. **Fix:** `_TypingIndicator`-Widget in `chat_view.dart` unter der Nachrichtenliste einfügen, das `room.onUpdate`-Stream abonniert und `room.typingUsers` anzeigt. #### [P2-3] Unread-Divider: Position off-by-one **Problem:** Divider erscheint *über* der Gruppe die das `fullyRead`-Event *enthält*, nicht darunter. Das bereits-gelesene Event liegt unter dem "Neue Nachrichten"-Strich. **Betroffene Datei:** `lib/features/chat/chat_view.dart`, Zeile ~715 **Fix:** Divider nach der Gruppe einsetzen, die das `fullyReadId`-Event enthält, nicht davor. #### [P2-4] Unread-Divider: Kein Auto-Scroll beim Öffnen **Problem:** Beim Öffnen eines Raums mit ungelesenen Nachrichten landet die View unten, nicht beim Divider. **FluffyChat-Referenz:** Initialer `scrollController.jumpTo()` zum Index des `fullyRead`-Events nach dem ersten Frame. **Fix:** In `initState`/`WidgetsBinding.addPostFrameCallback` zum Divider-Index springen wenn `_sessionHasUnread`. #### [P2-5] Gruppen-Read-Receipts fehlen **Problem:** ✓✓-Logik greift nur bei `room.isDirectChat`. In Gruppenräumen sehen eigene Nachrichten nie ✓✓. **FluffyChat-Referenz:** `SeenByRow` zeigt Avatare aller Leser unter der letzten Nachricht. **Fix:** Receipt-Prüfung auch in Gruppenräumen aktivieren; ggf. Avatar-Reihe unter letzter Nachricht. #### [P2-6] Notification-Cancellation beim Lesen fehlt **Problem:** Android-Notifications bleiben in der Benachrichtigungsleiste stehen, auch wenn der Chat geöffnet und die Nachrichten gelesen wurden. **FluffyChat-Referenz:** `backgroundPush?.cancelNotification(roomId)` in `_markRead()` **Fix:** In `_markRead()` in `chat_view.dart` die Android-Notification für `roomId` canceln. --- ### 🔵 P3 — Niedrig #### [P3-1] Presence: Kein Auto-Heartbeat **Problem:** `setPresence(online)` nur in Settings — Server setzt Client nach Timeout offline. **Fix:** Periodischer Timer (alle 60s) der `setPresence(online)` sendet solange App im Vordergrund. #### [P3-2] Presence: Kein App-Lifecycle-Hook **Problem:** Kein `WidgetsBindingObserver` — kein `unavailable` bei App-Hintergrund. **Fix:** `WidgetsBindingObserver.didChangeAppLifecycleState` in `matrix_client.dart` oder `app_shell.dart`. #### [P3-3] Markdown/`formatted_body` nicht gerendert **Problem:** `sendTextEvent` sendet nur plain text. Empfangene `formatted_body`-Felder werden nicht gerendert. **Fix:** Empfang: `flutter_html` oder `flutter_markdown` für `formatted_body`; Senden: simple Markdown-Erkennung im Composer. #### [P3-4] `requestFuture()` fehlt **Problem:** Kein Forward-Pagination-Mechanismus. Nach Jump-to-Event in der Vergangenheit kein Weg zurück. **Fix:** `timeline.requestFuture()` im Scroll-Listener für die Vorwärts-Richtung. #### [P3-5] `message_bubble.dart` — ungenutzter Code **Problem:** Veraltete WhatsApp-Style-Implementation koexistiert neben aktiver Discord-Style-Implementierung. **Fix:** Datei löschen oder auskommentieren. --- ## Statistik | Bereich | Implementiert | Fehlerhaft | Fehlend | |---|---|---|---| | Chat-Mechanik | Solide Basis | Edits, Typing, `requestFuture` | Jump-to-quote, Threads, Edited-Badge | | Read Receipts | DM-Logik ✓ | Gruppen, Off-by-one, Notif-Cancel | Seen-by-Avatare, Tooltip | | Presence | Anzeige ✓ | Broadcasting, Lifecycle | Heartbeat, Dot in Raumliste | | Benachrichtigungen | Local ✓ | Prefs ignoriert, Grouping | Remote Push, iOS, macOS | | Unread-Divider | Konzept ✓ | Position, Auto-Scroll | — | | E2EE | Stärkster Bereich | Incoming-Verif., Placeholder | Device-Trust-Indicator, Warn beim Senden | | Suche | API-Basis ✓ | — | Jump-to-message, Filter | **Implementierungsgrad gesamt: ~42 %** (inkl. Teilimplementierungen) --- ## Implementierungs-Fortschritt | ID | Beschreibung | Status | |---|---|---| | P0-1 | Incoming Key-Verification-Request-Handler | ✅ War bereits implementiert (`app_shell.dart`) | | P1-1 | Notification-Prefs auswerten | ✅ Implementiert (`notification_service.dart`) | | P1-2 | Edits rendern (`getDisplayEvent`) | ✅ Implementiert (`message_group.dart`) | | P1-3 | Encrypted-Placeholder + Recovery-Button | ✅ Implementiert (`message_group.dart`) | | P2-1 | Typing: `room.setTyping()` senden | ✅ Implementiert (`chat_composer.dart`) | | P2-2 | Typing: Display-Widget | ✅ Implementiert (`chat_view.dart` — `_TypingIndicator`) | | P2-3 | Unread-Divider: Position + leere fullyRead-Guard | ✅ Neu implementiert (`chat_view.dart`) | | P2-4 | Unread-Divider: Auto-Scroll (Schätzung) | ✅ Implementiert (`_scrollToUnread`) | | P2-5 | Gruppen-Read-Receipts (DM-Guard entfernt) | ✅ Implementiert (`chat_view.dart`) | | P2-6 | Notification-Cancellation beim Lesen | ✅ Implementiert (`chat_view.dart/_markRead`) | | P3-1 | Presence: Auto-Heartbeat (10s) | ✅ Implementiert (`app_shell.dart`) | | P3-2 | Presence: App-Lifecycle-Hook | ✅ Implementiert (`app_shell.dart` — `WidgetsBindingObserver`) | | P3-3 | HTML/Markdown (`_MatrixHtmlText`, `_PlainLinkText`) | ✅ Implementiert (`message_group.dart`) | | P3-4 | `requestFuture()` | ✅ Implementiert (`chat_view.dart/_onScroll`) | | P3-5 | `message_bubble.dart` entfernen | ⏳ Offen |