feat(flutter/library): API endpoints + Riverpod providers
LibraryApi wraps GET /api/home, /api/artists/{id}(/tracks),
/api/albums/{id}. dioProvider builds an authenticated dio (token
resolver reads session_token from secure storage on every request).
homeProvider, artistProvider(id), albumProvider(id) sit on top.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
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'),
|
||||
);
|
||||
});
|
||||
|
||||
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);
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user