mobile bluesky app made with flutter lazurite.stormlightlabs.org/
mobile bluesky flutter
at main 104 lines 4.2 kB view raw
1import 'dart:async'; 2 3import 'package:flutter/material.dart'; 4import 'package:lazurite/src/core/providers/app_lifecycle_provider.dart'; 5import 'package:lazurite/src/core/utils/logger_provider.dart'; 6import 'package:lazurite/src/features/auth/application/auth_providers.dart'; 7import 'package:lazurite/src/features/auth/domain/auth_state.dart'; 8import 'package:lazurite/src/features/settings/application/settings_providers.dart'; 9import 'package:riverpod_annotation/riverpod_annotation.dart'; 10 11part 'preference_sync_controller.g.dart'; 12 13/// Controller that manages automatic background synchronization of Bluesky preferences. 14/// 15/// Listens to app lifecycle changes and triggers preference sync when the app is resumed 16/// or when the user logs in. Also processes the preference sync queue to retry failed updates. 17@Riverpod(keepAlive: true) 18void preferenceSyncController(Ref ref) { 19 final logger = ref.watch(loggerProvider('PreferenceSync')); 20 var hasInitialized = false; 21 22 Future<void> runSync([String? ownerDid]) async { 23 logger.debug('runSync() called', {'ownerDid': ownerDid}); 24 25 final authState = ref.read(authProvider); 26 final effectiveOwnerDid = 27 ownerDid ?? ((authState is AuthStateAuthenticated) ? authState.session.did : null); 28 29 if (effectiveOwnerDid == null) { 30 logger.debug('Skipping sync: no ownerDid available'); 31 return; 32 } 33 34 try { 35 final repo = ref.read(blueskyPreferencesRepositoryProvider); 36 logger.debug('Syncing preferences from remote'); 37 await repo.syncPreferencesFromRemote(effectiveOwnerDid); 38 logger.info('Preferences synced successfully'); 39 40 logger.debug('Processing preference sync queue'); 41 await repo.processSyncQueue(effectiveOwnerDid); 42 logger.info('Preference sync queue processed'); 43 } catch (e, stack) { 44 logger.error('Failed to sync preferences on resume', e, stack); 45 } 46 } 47 48 ref.listen(appLifecycleProvider, (previous, next) { 49 if (next == AppLifecycleState.resumed) { 50 logger.debug('App resumed, triggering preference sync'); 51 unawaited(runSync()); 52 } 53 }); 54 55 ref.listen(authProvider, (previous, next) { 56 logger.debug('Auth state changed: ${previous.runtimeType}${next.runtimeType}'); 57 if (hasInitialized) { 58 final wasAuthed = previous is AuthStateAuthenticated; 59 final isAuthed = next is AuthStateAuthenticated; 60 logger.debug('wasAuthed=$wasAuthed, isAuthed=$isAuthed'); 61 62 if (wasAuthed != isAuthed) { 63 if (isAuthed) { 64 logger.info('User logged in - triggering preference sync'); 65 final newDid = next.session.did; 66 unawaited(runSync(newDid)); 67 } else { 68 logger.info('User logged out - clearing cached preferences'); 69 final oldDid = (previous as AuthStateAuthenticated).session.did; 70 unawaited(ref.read(blueskyPreferencesRepositoryProvider).clearAll(oldDid)); 71 } 72 } else if (isAuthed && wasAuthed) { 73 final prevSession = previous.session; 74 final nextSession = next.session; 75 if (prevSession.accessJwt != nextSession.accessJwt && prevSession.did == nextSession.did) { 76 logger.debug('Session refreshed - triggering sync to fetch preferences'); 77 unawaited(runSync(nextSession.did)); 78 } else if (prevSession.did != nextSession.did) { 79 logger.info('User switched - clearing old prefs and syncing new'); 80 unawaited(ref.read(blueskyPreferencesRepositoryProvider).clearAll(prevSession.did)); 81 unawaited(runSync(nextSession.did)); 82 } 83 } 84 } else { 85 logger.debug('Not initialized yet, skipping auth change handling'); 86 } 87 }); 88 89 Future.microtask(() async { 90 logger.debug('Controller initializing...'); 91 final authState = ref.read(authProvider); 92 logger.debug('Initial auth state: ${authState.runtimeType}'); 93 94 if (authState is AuthStateAuthenticated) { 95 logger.info('User is authenticated, running initial sync'); 96 await runSync(authState.session.did); 97 } else { 98 logger.info('User not authenticated, skipping initial sync'); 99 } 100 101 hasInitialized = true; 102 logger.info('Controller initialized'); 103 }); 104}