70 lines
3.0 KiB
Dart
70 lines
3.0 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../../database/database.dart';
|
|
import '../../features/records/records_service.dart';
|
|
import '../auth/auth_providers.dart';
|
|
import '../auth/auth_state.dart';
|
|
import '../cloud/firebase_account_sync_service.dart';
|
|
import '../github/github_auth_service.dart';
|
|
import '../github/github_sync_service.dart';
|
|
import 'firebase_sync_provider.dart';
|
|
import 'github_sync_provider.dart';
|
|
import 'r2_upload_service.dart';
|
|
import 'sync_bundle_worker.dart';
|
|
import 'sync_manager.dart';
|
|
import 'sync_models.dart';
|
|
import 'sync_outbox.dart';
|
|
|
|
final r2UploadServiceProvider = Provider<R2UploadService>((ref) => R2UploadService());
|
|
final syncBundleWorkerProvider = Provider<SyncBundleWorker>((ref) => SyncBundleWorker(ref.watch(databaseProvider)));
|
|
|
|
/// Cloud sync state is account-scoped. The Firebase UID is intentionally part
|
|
/// of the persisted namespace so signing out and into another account cannot
|
|
/// inherit the previous account's synced/pending/failed ride state.
|
|
final syncOutboxProvider = Provider<SyncOutbox>((ref) {
|
|
final prefs = ref.watch(sharedPreferencesProvider);
|
|
final user = ref.watch(currentUserProvider);
|
|
final namespace = user?.uid ?? 'local';
|
|
return SyncOutbox(prefs, storageNamespace: namespace);
|
|
});
|
|
|
|
final firebaseSyncProvider = Provider<FirebaseSyncProvider>((ref) => FirebaseSyncProvider(
|
|
db: ref.watch(databaseProvider),
|
|
authService: ref.watch(authServiceProvider),
|
|
bundleWorker: ref.watch(syncBundleWorkerProvider),
|
|
r2UploadService: ref.watch(r2UploadServiceProvider),
|
|
));
|
|
|
|
final firebaseAccountSyncServiceProvider = Provider<FirebaseAccountSyncService>((ref) => FirebaseAccountSyncService(
|
|
db: ref.watch(databaseProvider),
|
|
auth: ref.watch(authServiceProvider),
|
|
));
|
|
|
|
final githubSyncProvider = Provider<GitHubSyncProvider>((ref) => GitHubSyncProvider(
|
|
service: ref.watch(githubSyncServiceProvider),
|
|
auth: ref.watch(githubAuthServiceProvider),
|
|
));
|
|
|
|
final syncManagerProvider = ChangeNotifierProvider<SyncManager>((ref) {
|
|
final manager = SyncManager(
|
|
ref.watch(syncOutboxProvider),
|
|
initialProviders: [ref.watch(firebaseSyncProvider), ref.watch(githubSyncProvider)],
|
|
defaultProviderId: 'firebase',
|
|
);
|
|
final accountSync = ref.watch(firebaseAccountSyncServiceProvider);
|
|
ref.listen<AuthState>(authNotifierProvider, (previous, next) {
|
|
if (next.isAuthenticated && previous?.isAuthenticated != true) {
|
|
manager.retryAuthRequired();
|
|
accountSync.syncAccount().then((_) {}, onError: (_) {
|
|
// Profile/garage synchronization is downstream of riding and must
|
|
// never interrupt telemetry or ride persistence.
|
|
});
|
|
}
|
|
});
|
|
ref.onDispose(manager.dispose);
|
|
return manager;
|
|
});
|
|
|
|
final syncStateProvider = Provider<SyncManagerState>((ref) => ref.watch(syncManagerProvider).currentState);
|
|
final pendingSyncCountProvider = Provider<int>((ref) => ref.watch(syncStateProvider).pendingCount);
|
|
final isSyncProcessingProvider = Provider<bool>((ref) => ref.watch(syncStateProvider).isProcessing);
|