Files
minstrel/flutter_client/lib/library/library_providers.dart
T
bvandeusen ec0c10f312 feat(flutter): connection-error banner + 401-clears-session interceptor
ApiClient.buildDio takes on401; the library's dioProvider wires it to
the auth controller's clearSession. The router redirect already handles
navigation away from authed screens once the session goes null.
HomeScreen surfaces the banner on connection_refused with Retry +
Change URL.
2026-05-02 17:41:46 -04:00

61 lines
2.1 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../api/client.dart';
import '../api/endpoints/library.dart';
import '../auth/auth_provider.dart';
import '../models/album.dart';
import '../models/artist.dart';
import '../models/home_data.dart';
import '../models/track.dart';
/// Shared authenticated dio. This is the ONLY place tokenResolver is wired
/// to the secure-storage `session_token` read — every other endpoint
/// awaits `dioProvider.future` rather than constructing its own dio.
///
/// Riverpod will invalidate any FutureProvider that watches this when
/// the server URL changes; auth state changes don't need to invalidate
/// the provider because the resolver re-reads the token on every request.
final dioProvider = FutureProvider<Dio>((ref) async {
final url = await ref.watch(serverUrlProvider.future);
if (url == null || url.isEmpty) {
throw StateError('no server URL set');
}
final storage = ref.watch(secureStorageProvider);
return ApiClient.buildDio(
baseUrl: url,
tokenResolver: () async => storage.read(key: 'session_token'),
on401: () async => ref.read(authControllerProvider.notifier).clearSession(),
);
});
final libraryApiProvider = FutureProvider<LibraryApi>((ref) async {
return LibraryApi(await ref.watch(dioProvider.future));
});
final homeProvider = FutureProvider<HomeData>((ref) async {
return (await ref.watch(libraryApiProvider.future)).getHome();
});
final artistProvider =
FutureProvider.family<ArtistRef, String>((ref, id) async {
return (await ref.watch(libraryApiProvider.future)).getArtist(id);
});
final artistAlbumsProvider =
FutureProvider.family<List<AlbumRef>, String>((ref, id) async {
return (await ref.watch(libraryApiProvider.future)).getArtistAlbums(id);
});
final artistTracksProvider =
FutureProvider.family<List<TrackRef>, String>((ref, id) async {
return (await ref.watch(libraryApiProvider.future)).getArtistTracks(id);
});
final albumProvider =
FutureProvider.family<({AlbumRef album, List<TrackRef> tracks}), String>(
(ref, id) async {
return (await ref.watch(libraryApiProvider.future)).getAlbum(id);
},
);