feat: Phase 2 complete — calls, media, spaces, persistence, chat improvements

- LiveKit/MatrixRTC voice+video calls with full call screen UI
- Incoming call overlay (accept/decline)
- Media upload/download — file picker, image rendering, file download
- Spaces navigation — space list + expandable child rooms
- Drift persistence — rooms + messages written on every sync
- Sync persistence auto-starts on login and session restore
- Chat: typing indicators, long-press menu, reply, emoji reactions
- User search dialog + start DM from rooms screen
- Android: INTERNET + CAMERA + RECORD_AUDIO permissions in main manifest
- Emoji picker for reactions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-02 06:48:03 +10:00
parent 8f13c725a4
commit f12a7ac1fd
20 changed files with 2458 additions and 191 deletions

View File

@@ -1,4 +1,4 @@
// Version: 1.0.0 | Created: 2026-04-01
// Version: 1.1.0 | Created: 2026-04-01
// Riverpod notifier that owns the auth state machine.
// All login/logout/session-restore transitions go through here.
@@ -6,6 +6,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../features/auth/data/auth_repository.dart';
import '../../features/auth/domain/auth_failure.dart';
import '../storage/sync_persistence_service.dart';
import 'auth_state.dart';
import 'secure_storage.dart';
@@ -48,6 +49,9 @@ class AuthNotifier extends _$AuthNotifier {
accessToken: credentials.accessToken,
deviceId: credentials.deviceId,
);
// Resume background persistence for the restored session.
ref.read(syncPersistenceServiceProvider).start();
} on AuthFailure {
// Stored credentials are invalid; force re-login.
await storage.clearCredentials();
@@ -84,6 +88,9 @@ class AuthNotifier extends _$AuthNotifier {
accessToken: response.accessToken,
deviceId: response.deviceId,
);
// Start background sync-to-database persistence now that we are logged in.
ref.read(syncPersistenceServiceProvider).start();
} on AuthFailure catch (failure) {
state = AuthState.unauthenticated(failure: failure.userMessage);
}