import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; /// Online if at least one connectivity result is non-none. /// connectivity_plus reports the union (wifi, mobile, vpn, etc.) — operator /// chose "no Wi-Fi gate" for #357, so any connection means "go ahead and /// pull/cache". /// /// IMPORTANT: onConnectivityChanged only emits on *changes*, not on /// subscription. Without seeding an initial value via checkConnectivity(), /// any consumer using `ref.read(connectivityProvider.future)` would /// block until the OS happened to report a connectivity flip — which /// is exactly what made album/artist/playlist detail screens spin /// forever for tiles tapped before the first event landed. final connectivityProvider = StreamProvider((ref) async* { final c = Connectivity(); bool isOnline(List rs) => rs.any((r) => r != ConnectivityResult.none); // checkConnectivity() goes over a platform channel and on some // Android builds it can stall. Fall back to "assume online" after // 2s so consumers waiting on .future never block forever — being // wrong about connectivity costs at most one failed request, but // being stuck spins the UI indefinitely. try { final initial = await c.checkConnectivity().timeout( const Duration(seconds: 2), onTimeout: () => const [ConnectivityResult.wifi], ); yield isOnline(initial); } catch (_) { yield true; } yield* c.onConnectivityChanged.map(isOnline); });