import 'dart:async'; import 'package:flutter/foundation.dart' show debugPrint; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart' as http; import 'package:supabase_flutter/supabase_flutter.dart'; import '../brick/cache_warmer.dart'; import '../brick/repository.dart'; import 'stream_recovery.dart'; /// Current online/offline status. /// Defaults to true so the UI doesn't flash an offline banner on startup. final isOnlineProvider = StateProvider((ref) => true); /// Activating this provider starts a periodic connectivity poll. /// Watch it from the root widget to keep it alive. final connectivityMonitorProvider = Provider.autoDispose((ref) { // Wire up the global online check for StreamRecoveryWrapper so all stream // wrappers can suppress recovery while offline without per-instance setup. StreamRecoveryWrapper.setIsOnlineCallback(() => ref.read(isOnlineProvider)); bool previouslyOnline = true; Future check() async { final online = await ConnectivityMonitor.check(); final wasOnline = ref.read(isOnlineProvider); if (online != wasOnline) { ref.read(isOnlineProvider.notifier).state = online; } if (previouslyOnline && !online) { _onDisconnected(); } if (!previouslyOnline && online) { _onReconnected(); } previouslyOnline = online; } // Run immediately, then every 5 seconds. check(); final timer = Timer.periodic(const Duration(seconds: 5), (_) => check()); ref.onDispose(timer.cancel); }); /// Pings the app's own backend to determine online status. class ConnectivityMonitor { static Future check() async { try { final res = await http .head(Uri.parse('https://tasq.crmc.ph')) .timeout(const Duration(seconds: 5)); return res.statusCode < 500; } catch (_) { return false; } } } void _onDisconnected() { debugPrint('[Connectivity] Went offline — pausing Brick request queue'); // Stop the retry loop so the queue doesn't spam network errors while offline. // Queued writes are preserved in SQLite and will sync when _onReconnected fires. AppRepository.offlineQueue?.stop(); } void _onReconnected() { debugPrint('[Connectivity] Back online — queued writes will sync via Brick'); if (!AppRepository.isConfigured) return; // Resume the Brick HTTP queue so queued writes (e.g. offline task creation) // are replayed against Supabase now that the network is available again. AppRepository.offlineQueue?.start(); // Restart any Supabase realtime streams that were suppressed while offline. // Streams that disconnected due to no network are NOT in an error-retry loop // (recovery was suppressed); this kick-starts them back to live updates. StreamRecoveryWrapper.notifyAllOnlineRestored(); // Re-warm the Brick cache so the local SQLite mirror reflects any changes // that happened on the server while we were offline. Fire-and-forget — it // runs in the background and never throws. final user = Supabase.instance.client.auth.currentUser; if (user != null) { CacheWarmer.warmAll(Supabase.instance.client); } }