3c7eb9ddca
- CallSignalingService/callSignalingProvider und VoiceChannelService/ voiceChannelProvider als einzige oeffentliche Schnittstellen - voip_manager.dart / livekit_call_manager.dart in ihre Module verschoben, Logik unangetastet (nur Klassen-Koepfe, @override, Imports, Provider-Namen) - Alle Konsumenten entkoppelt; Kompositions-Punkt matrix_client.dart als dokumentierte Ausnahme. analyze sauber, 29 Tests gruen, Windows-Start ok. Call-Klick-/Geraetetest steht aus (PROGRESS.md)
182 lines
8.8 KiB
Markdown
182 lines
8.8 KiB
Markdown
# M2 – Modul-Schnitt (Entwurf)
|
||
|
||
> **STATUS 2026-07-06: Pilot (Schritt 1) UMGESETZT.** Die Module
|
||
> `call_signaling` (`lib/features/call_signaling/`: `CallSignalingService`
|
||
> + `callSignalingProvider` + Implementierung `voip_manager.dart`) und
|
||
> `voice_channel` (`lib/features/voice_channel/`: `VoiceChannelService` +
|
||
> `voiceChannelProvider` + Implementierung `livekit_call_manager.dart`)
|
||
> existieren; ALLE Konsumenten (Shell, Call-UI, Rooms-Panel, Chat-Header,
|
||
> Settings) gehen nur noch über die Provider/Interfaces, kein direkter
|
||
> Implementierungs-Import mehr (einzige dokumentierte Ausnahme:
|
||
> Kompositions-Punkt `matrix_client.dart`). Bewusste Abweichungen vom
|
||
> Entwurf unten (Verhaltensgleichheit vor Schönheit, heiliger Call-Pfad):
|
||
> ChangeNotifier statt Streams, Methodennamen wie im Bestand
|
||
> (`startCall`/`hangUp` statt `join`/`leave`), `CallSession`/LiveKit-`Room`
|
||
> bleiben in den Schnittstellen sichtbar, weil die UI direkt rendert.
|
||
> Echter Call-/Voice-Channel-Test steht aus (Gerät bzw. Klick-Test) –
|
||
> siehe PROGRESS.md 2026-07-06. Schritte 2–5 unten sind weiter offen.
|
||
|
||
Stand: 2026-07-03. Reine Schnittstellen-Planung, noch kein Umbau. Grundlage:
|
||
Ist-Analyse in `PROGRESS.md` (Eintrag „M2: Ist-Analyse der Architektur
|
||
geschrieben"). Leitprinzip (Bernd, `CLAUDE.md`): jedes Modul muss sich in
|
||
einem Jahr komplett neu schreiben lassen, ohne andere Module anzufassen.
|
||
Andere Module dürfen daher nur die hier genannte öffentliche Schnittstelle
|
||
importieren, nie interne Dateien.
|
||
|
||
Korrektur zur Ist-Analyse: der Import von `rooms_provider.dart` in
|
||
`app_state.dart` ist **kein** toter Altlast-Import, wie dort vermutet –
|
||
`voiceParticipantsProvider` (Zeile 160) nutzt `roomListProvider` daraus, um
|
||
bei jedem Sync neu zu bauen. Der Eintrag in PROGRESS.md wird beim nächsten
|
||
Durchgang korrigiert.
|
||
|
||
## Wichtige Erkenntnis vor dem Schnitt: „Calls" ist eigentlich ZWEI Features
|
||
|
||
Beim genaueren Lesen von `voip_manager.dart` und `livekit_call_manager.dart`
|
||
zeigt sich: das sind keine zwei Hälften derselben Sache, sondern zwei
|
||
unabhängige Call-Mechanismen, die zufällig beide „Call" heißen:
|
||
|
||
- **`PyramidVoipManager`** – natives Matrix-VoIP (`m.call.*`-Events über das
|
||
matrix-SDK, direkte 1:1-WebRTC-Peer-Connection, kein SFU). Vermutlich für
|
||
spontane 1:1-Anrufe gedacht.
|
||
- **`LiveKitCallManager`** – SFU-basierte, dauerhafte Voice-Channels (LiveKit-
|
||
Server-Raum, Presence über Matrix-State-Events, Screensharing, Mehrpersonen).
|
||
Das ist der Discord-artige Voice-Channel aus M3/M4.
|
||
|
||
Beide Module sollten **getrennt** bleiben, nicht zu einem „calls"-Modul
|
||
verschmolzen werden. Nur die UI (`call_ui`) darf beide kennen, falls sie
|
||
gemeinsam dargestellt werden müssen (z. B. „du bist in einem Voice-Channel,
|
||
jemand ruft dich per 1:1-VoIP an").
|
||
|
||
## Modul-Liste mit öffentlicher Schnittstelle (Entwurf)
|
||
|
||
### 1. `call_signaling` (Matrix-1:1-VoIP)
|
||
**Ersetzt:** `core/voip_manager.dart`
|
||
**Öffentliche Schnittstelle (Ausschnitt):**
|
||
```dart
|
||
abstract class CallSignalingService {
|
||
Stream<CallSession?> get currentCallStream;
|
||
bool get isMicMuted;
|
||
bool get isCameraMuted;
|
||
Future<void> startCall(String roomId, {bool video});
|
||
Future<void> hangup();
|
||
Future<void> toggleMic();
|
||
Future<void> toggleCamera();
|
||
Future<void> toggleScreenSharing(BuildContext? context);
|
||
RTCVideoRenderer get localRenderer; // bleibt vorerst WebRTC-typisiert,
|
||
RTCVideoRenderer get remoteRenderer; // da UI direkt rendert
|
||
}
|
||
```
|
||
Interna (ICE-Server-Merge, `MediaDevicesWrapper`, Geräte-Prefs aus
|
||
`SharedPreferences`) bleiben privat im Modul. Geräte-Prefs sollten künftig
|
||
über die `storage`-Fassade laufen statt direktem `SharedPreferences`-Zugriff
|
||
(aktuell Zeile 260, 447).
|
||
|
||
### 2. `voice_channel` (LiveKit-SFU, Discord-artige Kanäle)
|
||
**Ersetzt:** `core/livekit_call_manager.dart`
|
||
**Öffentliche Schnittstelle (Ausschnitt):**
|
||
```dart
|
||
abstract class VoiceChannelService {
|
||
Stream<VoiceChannelState> get stateStream; // isActive, isMuted, participants…
|
||
Future<void> join({required String roomName, required String matrixRoomId, ...});
|
||
Future<void> leave();
|
||
Future<void> toggleMute();
|
||
Future<void> toggleDeafen();
|
||
Future<void> toggleCamera();
|
||
Future<void> toggleScreenShare();
|
||
Future<void> setPublishQuality(String key); // Streamer-Seite (M4)
|
||
Future<void> setSubscribeQuality(String key); // Empfänger-Seite (M4)
|
||
Future<void> setOutputVolume(double v);
|
||
}
|
||
```
|
||
Presence-Writing (`_writePresence`, Matrix-State-Event
|
||
`io.pyramid.voice.presence`) bleibt intern, aber nutzt eine injizierte
|
||
`Client`-Referenz statt globalem Singleton-Zugriff – macht das Modul für
|
||
Tests austauschbar.
|
||
|
||
### 3. `call_ui`
|
||
**Ersetzt:** `features/call/voice_channel.dart`, `features/call/mini_call_widget.dart`
|
||
Konsumiert ausschließlich `CallSignalingService` + `VoiceChannelService` über
|
||
Riverpod-Provider (`callSignalingProvider`, `voiceChannelProvider`). Keine
|
||
direkten Importe von `core/voip_manager.dart`/`core/livekit_call_manager.dart`
|
||
mehr – heute importieren `chat_view.dart`, `matrix_client.dart` und
|
||
`settings_modal.dart` diese Dateien direkt, das entfällt.
|
||
|
||
### 4. `settings` (aufgesplittet)
|
||
Kein eigenes fachliches Modul, sondern reine Aggregations-UI. Jede Sektion
|
||
wird eine eigene Datei/Klasse mit einer schmalen `Widget build(...)`-Fläche,
|
||
die ihrerseits nur die Provider ihres Fachmoduls konsumiert (z. B.
|
||
`_VoiceSection` nutzt künftig `voiceChannelProvider`/`callSignalingProvider`
|
||
statt der Manager direkt). Vorschlag für Dateien:
|
||
`settings/profile_section.dart`, `settings/notifications_section.dart`,
|
||
`settings/appearance_section.dart`, `settings/sessions_section.dart`,
|
||
`settings/account_section.dart`, `settings/voice_section.dart`,
|
||
`settings/about_section.dart`.
|
||
|
||
### 5. `verification` (neu, aus Settings herausgelöst)
|
||
**Quelle:** `widgets/settings_modal.dart` Zeile 2921–4545 (SAS-Dialog,
|
||
QR-Anzeige, Emoji-Vergleich, Recovery-Key-Flow).
|
||
```dart
|
||
abstract class VerificationService {
|
||
Future<void> startSasVerification(DeviceKeys device);
|
||
Future<void> confirmSas();
|
||
Future<void> declineSas();
|
||
Stream<VerificationStep> get stepStream;
|
||
}
|
||
```
|
||
Eigenständig, weil SAS/QR-Verifikation künftig auch außerhalb der Settings
|
||
gebraucht werden könnte (z. B. beim Login auf einem neuen Gerät –
|
||
`bootstrap_dialog.dart` macht heute schon etwas Ähnliches separat).
|
||
|
||
### 6. `storage` (Fassade, kein Rewrite)
|
||
**Ausbau von:** `core/settings_prefs.dart`
|
||
```dart
|
||
abstract class Prefs {
|
||
Future<bool> getBool(String key, {bool fallback});
|
||
Future<void> setBool(String key, bool value);
|
||
// … String, double, StringSet analog zu BoolPref/StringSetPref
|
||
}
|
||
```
|
||
Ziel ist NICHT, `SharedPreferences` zu ersetzen, sondern die bereits
|
||
vorhandene `BoolPref`/`StringSetPref`-Abstraktion zur Pflicht zu machen.
|
||
Die 12 identifizierten Direktzugriffsstellen (u. a. `voip_manager.dart:260`,
|
||
`livekit_call_manager.dart:246`, `settings_modal.dart:1804/1860/1870`) werden
|
||
schrittweise umgestellt – **nicht** in diesem Schritt, sondern sobald das
|
||
jeweilige Modul (z. B. `call_signaling`) ohnehin angefasst wird.
|
||
Krypto-/Access-Token-Speicherung (`flutter_secure_storage`,
|
||
`matrix_client.dart`) bleibt bewusst außen vor – hängt an der noch offenen
|
||
SQLCipher-Frage (M1) und wird dort separat behandelt, nicht hier.
|
||
|
||
### 7. `auth`
|
||
**Dateien:** `features/auth/login_notifier.dart`, `login_page.dart`,
|
||
`server_page.dart`, `bootstrap_dialog.dart` (Bootstrap-Teil, Verifikations-Teil
|
||
wandert ggf. zu `verification`, s. o.). Schnittstelle bleibt der bereits
|
||
vorhandene `matrixClientProvider`/`login_notifier`-Zustandsautomat – heute
|
||
schon relativ sauber gekapselt, kein akuter Handlungsbedarf.
|
||
|
||
### 8. `push`
|
||
**Dateien:** `core/background_push.dart`, `core/fcm_push_service.dart`,
|
||
`core/notification_service.dart`. Bereits über eigene Dateien getrennt
|
||
(nativ vs. Flutter-Engine, siehe Memory „Pyramid Push"). Einzige Lücke:
|
||
eigener `sqflite`-Zugriff in `background_push.dart` statt gemeinsamer
|
||
DB-Schicht – bewusst so gewollt (Background-Isolate-Zwang), daher **kein**
|
||
Refactoring-Kandidat, nur dokumentieren.
|
||
|
||
### 9. `chat_timeline` / `rooms`
|
||
Niedrigste Priorität für den Pilot-Umbau, da laut Ist-Analyse strukturell
|
||
am wenigsten verwoben (Hauptproblem dort ist Dateigröße + Duplikate, nicht
|
||
Modul-Kopplung). Wird nach dem Call-Pilot angegangen.
|
||
|
||
## Reihenfolge-Vorschlag für die Umsetzung
|
||
|
||
1. **Pilot: `call_signaling` + `voice_channel` + `call_ui`** (Punkt „Call-Schicht
|
||
entwirren" in ROADMAP.md) – kleinster klar abgegrenzter Schnitt, deckt
|
||
gleich zwei ROADMAP-Punkte ab (Modul-Schnitt beweisen + Call-Entwirrung).
|
||
2. `settings_modal.dart` aufsplitten (reine Datei-Teilung, geringes Risiko,
|
||
keine Verhaltensänderung).
|
||
3. `verification` aus Settings herauslösen.
|
||
4. `storage`-Fassade schrittweise erzwingen, immer im Zuge anderer Umbauten.
|
||
5. `chat_timeline`/`rooms` zuletzt.
|
||
|
||
**Bernd-Entscheidung nötig:** siehe Frage in PROGRESS.md – ob Punkt 1
|
||
(Call-Pilot) so wie hier vorgeschlagen als Nächstes umgesetzt werden soll.
|