diff --git a/lib/provider/spotify/album/favorite.dart b/lib/provider/spotify/album/favorite.dart new file mode 100644 index 00000000..af37894e --- /dev/null +++ b/lib/provider/spotify/album/favorite.dart @@ -0,0 +1,61 @@ +part of '../spotify.dart'; + +class FavoriteAlbumState extends PaginatedState { + FavoriteAlbumState({ + required super.items, + required super.offset, + required super.limit, + }); + + @override + FavoriteAlbumState copyWith({ + items, + offset, + limit, + }) { + return FavoriteAlbumState( + items: items ?? this.items, + offset: offset ?? this.offset, + limit: limit ?? this.limit, + ); + } +} + +class FavoriteAlbumNotifier + extends PaginatedAsyncNotifier + with SpotifyMixin { + @override + Future> fetch(int offset, int limit) { + return spotify.me + .savedAlbums() + .getPage(limit, offset) + .then((value) => value.items?.toList() ?? []); + } + + @override + build() async { + ref.watch(spotifyProvider); + return FavoriteAlbumState( + items: await fetch(0, 20), + offset: 0, + limit: 20, + ); + } + + Future saveAlbums(List ids) async { + if (state.value == null) return; + + await spotify.me.saveAlbums(ids); + + state = await AsyncValue.guard(() async { + final albums = await spotify.albums.list(ids); + + return state.value!.copyWith( + items: [ + ...state.value!.items, + ...albums, + ], + ); + }); + } +} diff --git a/lib/provider/spotify/spotify.dart b/lib/provider/spotify/spotify.dart new file mode 100644 index 00000000..091ff897 --- /dev/null +++ b/lib/provider/spotify/spotify.dart @@ -0,0 +1,10 @@ +library spotify; + +import 'package:spotify/spotify.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/provider/spotify_provider.dart'; + +part 'album/favorite.dart'; +part 'utils/mixin.dart'; +part 'utils/state.dart'; +part 'utils/provider.dart'; diff --git a/lib/provider/spotify/utils/mixin.dart b/lib/provider/spotify/utils/mixin.dart new file mode 100644 index 00000000..db41daaf --- /dev/null +++ b/lib/provider/spotify/utils/mixin.dart @@ -0,0 +1,5 @@ +part of '../spotify.dart'; + +mixin SpotifyMixin on AsyncNotifier { + SpotifyApi get spotify => ref.read(spotifyProvider); +} diff --git a/lib/provider/spotify/utils/provider.dart b/lib/provider/spotify/utils/provider.dart new file mode 100644 index 00000000..08cd022d --- /dev/null +++ b/lib/provider/spotify/utils/provider.dart @@ -0,0 +1,23 @@ +part of '../spotify.dart'; + +abstract class PaginatedAsyncNotifier> + extends AsyncNotifier { + Future> fetch(int offset, int limit); + + Future fetchMore() async { + if (state.value == null || !state.value!.hasMore) return; + + await update( + (state) async { + final items = await fetch(state.offset + state.limit, state.limit); + return state.copyWith( + items: [ + ...state.items, + ...items, + ], + offset: state.offset + state.limit, + ) as T; + }, + ); + } +} diff --git a/lib/provider/spotify/utils/state.dart b/lib/provider/spotify/utils/state.dart new file mode 100644 index 00000000..002323f3 --- /dev/null +++ b/lib/provider/spotify/utils/state.dart @@ -0,0 +1,16 @@ +part of '../spotify.dart'; + +abstract class PaginatedState { + final List items; + final int offset; + final int limit; + final bool hasMore; + + PaginatedState({ + required this.items, + required this.offset, + required this.limit, + }) : hasMore = items.length >= limit; + + PaginatedState copyWith({List? items, int? offset, int? limit}); +}