feat: Push als Chat-Verlauf - mehrere Nachrichten, voller Text, Bildvorschau, echtes "Gelesen"

Bernds Beta-Feedback: pro Raum wurde jede Nachricht durch die naechste ersetzt
und auf 100 Zeichen gekuerzt, ohne Bild. Jetzt:
- NotificationHelper: MessagingStyle mit den letzten 8 Nachrichten pro Raum
  (Verlauf in SharedPreferences, nur solange die Benachrichtigung sichtbar ist),
  gleiche eventId ersetzt (Platzhalter -> Klartext), nur Neues klingelt.
- notification_content.dart: Text bis 1000 Zeichen, Antwort-Zitat entfernt,
  Medien-Labels, Vorschau-Einstellung auch bei gekillter App; Bild (E2EE
  entschluesselt) + Avatar per FileProvider an die System-UI.
- "Gelesen" setzt eine echte Lesebestaetigung (Haupt-Engine bzw. BgEngine).
- Laufende App holt genau das gepushte Event statt room.lastEvent.
- Debug-only DebugNotifyReceiver zum Testen per adb ohne Login.
Emulator (API 36): Verlauf, Ersetzen, Bild, Avatar, Gelesen geprueft;
9 neue Tests. Echtes Geraet (Bernd) steht aus.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Bernd Steckmeister
2026-10-07 16:27:56 +02:00
co-authored by Claude Opus 5.5
parent 460477204b
commit ef1d881967
12 changed files with 1103 additions and 170 deletions
+35 -1
View File
@@ -70,6 +70,39 @@ Ergebnis: Die Benachrichtigung erscheint ~4 s nach der Nachricht **direkt mit
echtem Text** (kein „Neue Nachricht"-Zwischenschritt). Die ~4 s sind der
Engine-Bootstrap (~1,7 s) + Client-Init/Entschlüsselung (~2,3 s).
## Darstellung: Chat-Verlauf statt Einzelnachricht (seit 2026-10-07)
Auf Bernds Beta-Feedback („nur eine Nachricht, wenig Text, kein Bild“):
- **Pro Raum ein Chat-Verlauf** (Android `MessagingStyle`) mit den letzten 8
Nachrichten, Absendername + Avatar je Nachricht, Gruppenname als Titel.
Der Verlauf liegt in SharedPreferences (`pyramid_notif_history`), weil bei
gekillter App jeder Push in einem neuen Prozess ankommt. Er wird nur
fortgeführt, solange die Benachrichtigung noch sichtbar ist (weggewischt
oder Raum geöffnet → nächster Push beginnt neu).
- **Gleiche eventId = Aktualisierung**, nicht neue Nachricht: der
„Neue Nachricht“-Platzhalter wird durch den Klartext ersetzt, später kommen
lautlos Avatar/Bild dazu. Nur wirklich neue Nachrichten klingeln
(`setOnlyAlertOnce(!isNew)`).
- **Text:** nicht mehr auf 100 Zeichen gekürzt (Deckel 1000), Antwort-Zitat
entfernt, Medien als „📷 Foto“/„🎤 Sprachnachricht“/„📎 datei.pdf“ usw.
Logik in `lib/core/notification_content.dart` (Tests:
`test/notification_content_test.dart`). Einstellung „Nachrichtenvorschau“
gilt jetzt auch bei gekillter App.
- **Bilder/Avatare:** Dart legt sie unter `<cache>/downloads/notif/` ab
(Vorschaubild, bei E2EE entschlüsselt; Avatar aus dem MediaCache), native
reicht sie per FileProvider-URI an die System-UI weiter
(`grantUriPermission("com.android.systemui")`). Dateien älter als 2 Tage
werden aufgeräumt. Scheitert das Anzeigen mit Medien, fällt
`NotificationHelper` auf reinen Text zurück.
- **„Gelesen“** setzt jetzt eine echte Lesebestätigung bis zur neuesten
Nachricht (Haupt-Engine `markReadFromNotification` bzw. BgEngine
`markRead`), statt nur zu schließen.
- **Testen ohne Login (nur Debug-Build):** `DebugNotifyReceiver`
(`android/app/src/debug/`), z. B.
`adb shell "am broadcast -n chat.pyramid.pyramid/.DebugNotifyReceiver --es roomName Familie --es sender Uta --es event e1 --ez avatar true --es body 'Hallo'"`
(`--ez image true` für ein Testbild). Nicht im Release-APK.
## Verschlüsselt antworten (gekillt, vollständig still)
- Die Reply-Action ist ein **BroadcastReceiver** (`getBroadcast` → `ReplyReceiver`),
@@ -103,7 +136,8 @@ Engine-Bootstrap (~1,7 s) + Client-Init/Entschlüsselung (~2,3 s).
| `android/.../PushService.kt` | FCM-Empfang, Heartbeat-Check, decrypt-first-Routing |
| `android/.../BgEngine.kt` | Headless-Engine-Bootstrap, Fallback-Platzhalter |
| `android/.../ReplyReceiver.kt` | Stilles verschlüsseltes Antworten (Broadcast) |
| `android/.../NotificationHelper.kt` | Native Benachrichtigung (Reply/Tap/Dismiss, setOnlyAlertOnce) |
| `android/.../NotificationHelper.kt` | Native Benachrichtigung: Chat-Verlauf (MessagingStyle), Bilder, Antworten/Gelesen/Tippen |
| `lib/core/notification_content.dart` | Inhalt einer Benachrichtigung (Text, Medien-Labels, Bild/Avatar-Dateien) |
| `android/.../MainActivity.kt` | MethodChannel `install`, Cold-Start-Reply-Fallback |
| `lib/core/background_push.dart` | Dart-Hintergrund-Isolate: decrypt + reply |
| `lib/core/fcm_push_service.dart` | Pusher-Registrierung bei Sygnal |