Files
minstrel/flutter_client/lib/cache/connectivity_provider.dart
bvandeusen 3c0806d8fd diag(flutter): time-box connectivity check + trace album cold-cache path
Two changes to surface where detail-screen spinners hang:

1. Connectivity().checkConnectivity() goes over a platform channel
   that on some Android builds stalls. Wrap with a 2s timeout and
   default to "online" if it times out — being wrong about
   connectivity costs at most one failed fetch, but being stuck
   spins the UI forever.

2. albumProvider's cold-cache flow now debugPrints at every step:
   drift miss → connectivity result → API call → drift write → ack
   the re-emit. Also adds a 10s timeout on the API fetch and a 3s
   timeout on the connectivity await so a hang surfaces as an
   error-yielded empty AlbumRef instead of an infinite spinner.

Once the operator's next test produces logs we can pinpoint which
step is hanging. The diagnostic prints stay until the issue's root
cause is confirmed; will be removed in a follow-up.
2026-05-11 08:28:32 -04:00

36 lines
1.5 KiB
Dart

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<bool>((ref) async* {
final c = Connectivity();
bool isOnline(List<ConnectivityResult> 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);
});