mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-08 16:24:36 +00:00
feat: make many provider autoDispose after 5 minutes of no usage
This commit is contained in:
parent
36316f5e94
commit
75b05f3dc8
@ -28,15 +28,14 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final controller = useTextEditingController();
|
final searchTerm = ref.watch(searchTermStateProvider);
|
||||||
|
final controller = useTextEditingController(text: searchTerm);
|
||||||
|
|
||||||
ref.watch(AuthenticationNotifier.provider);
|
ref.watch(AuthenticationNotifier.provider);
|
||||||
final authenticationNotifier =
|
final authenticationNotifier =
|
||||||
ref.watch(AuthenticationNotifier.provider.notifier);
|
ref.watch(AuthenticationNotifier.provider.notifier);
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
|
||||||
final searchTerm = ref.watch(searchTermStateProvider);
|
|
||||||
|
|
||||||
final searchTrack = ref.watch(searchProvider(SearchType.track));
|
final searchTrack = ref.watch(searchProvider(SearchType.track));
|
||||||
final searchAlbum = ref.watch(searchProvider(SearchType.album));
|
final searchAlbum = ref.watch(searchProvider(SearchType.album));
|
||||||
final searchPlaylist = ref.watch(searchProvider(SearchType.playlist));
|
final searchPlaylist = ref.watch(searchProvider(SearchType.playlist));
|
||||||
|
|||||||
@ -24,8 +24,8 @@ class AlbumTracksState extends PaginatedState<Track> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlbumTracksNotifier
|
class AlbumTracksNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<Track,
|
||||||
extends FamilyPaginatedAsyncNotifier<Track, AlbumTracksState, AlbumSimple> {
|
AlbumTracksState, AlbumSimple> {
|
||||||
AlbumTracksNotifier() : super();
|
AlbumTracksNotifier() : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -39,6 +39,8 @@ class AlbumTracksNotifier
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
build(arg) async {
|
build(arg) async {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
ref.watch(spotifyProvider);
|
ref.watch(spotifyProvider);
|
||||||
final tracks = await fetch(arg, 0, 20);
|
final tracks = await fetch(arg, 0, 20);
|
||||||
return AlbumTracksState(
|
return AlbumTracksState(
|
||||||
@ -50,7 +52,7 @@ class AlbumTracksNotifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final albumTracksProvider = AsyncNotifierProviderFamily<AlbumTracksNotifier,
|
final albumTracksProvider = AutoDisposeAsyncNotifierProviderFamily<
|
||||||
AlbumTracksState, AlbumSimple>(
|
AlbumTracksNotifier, AlbumTracksState, AlbumSimple>(
|
||||||
() => AlbumTracksNotifier(),
|
() => AlbumTracksNotifier(),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -24,8 +24,8 @@ class ArtistAlbumsState extends PaginatedState<Album> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistAlbumsNotifier
|
class ArtistAlbumsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
|
||||||
extends FamilyPaginatedAsyncNotifier<Album, ArtistAlbumsState, String> {
|
Album, ArtistAlbumsState, String> {
|
||||||
ArtistAlbumsNotifier() : super();
|
ArtistAlbumsNotifier() : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -40,6 +40,8 @@ class ArtistAlbumsNotifier
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
build(arg) async {
|
build(arg) async {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
ref.watch(spotifyProvider);
|
ref.watch(spotifyProvider);
|
||||||
ref.watch(
|
ref.watch(
|
||||||
userPreferencesProvider.select((s) => s.recommendationMarket),
|
userPreferencesProvider.select((s) => s.recommendationMarket),
|
||||||
@ -54,7 +56,7 @@ class ArtistAlbumsNotifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final artistAlbumsProvider = AsyncNotifierProviderFamily<ArtistAlbumsNotifier,
|
final artistAlbumsProvider = AutoDisposeAsyncNotifierProviderFamily<
|
||||||
ArtistAlbumsState, String>(
|
ArtistAlbumsNotifier, ArtistAlbumsState, String>(
|
||||||
() => ArtistAlbumsNotifier(),
|
() => ArtistAlbumsNotifier(),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
final artistProvider = FutureProvider.family((ref, String artistId) {
|
final artistProvider =
|
||||||
|
FutureProvider.autoDispose.family((ref, String artistId) {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
final spotify = ref.watch(spotifyProvider);
|
final spotify = ref.watch(spotifyProvider);
|
||||||
|
|
||||||
return spotify.artists.get(artistId);
|
return spotify.artists.get(artistId);
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
final relatedArtistsProvider =
|
final relatedArtistsProvider = FutureProvider.autoDispose
|
||||||
FutureProvider.family<List<Artist>, String>((ref, artistId) async {
|
.family<List<Artist>, String>((ref, artistId) async {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
final spotify = ref.watch(spotifyProvider);
|
final spotify = ref.watch(spotifyProvider);
|
||||||
final artists = await spotify.artists.relatedArtists(artistId);
|
final artists = await spotify.artists.relatedArtists(artistId);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
final artistTopTracksProvider = FutureProviderFamily<List<Track>, String>(
|
final artistTopTracksProvider =
|
||||||
|
FutureProvider.autoDispose.family<List<Track>, String>(
|
||||||
(ref, artistId) async {
|
(ref, artistId) async {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
final spotify = ref.watch(spotifyProvider);
|
final spotify = ref.watch(spotifyProvider);
|
||||||
final market = ref
|
final market = ref
|
||||||
.watch(userPreferencesProvider.select((s) => s.recommendationMarket));
|
.watch(userPreferencesProvider.select((s) => s.recommendationMarket));
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class CategoryPlaylistsState extends PaginatedState<PlaylistSimple> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CategoryPlaylistsNotifier extends FamilyPaginatedAsyncNotifier<
|
class CategoryPlaylistsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
|
||||||
PlaylistSimple, CategoryPlaylistsState, String> {
|
PlaylistSimple, CategoryPlaylistsState, String> {
|
||||||
CategoryPlaylistsNotifier() : super();
|
CategoryPlaylistsNotifier() : super();
|
||||||
|
|
||||||
@ -44,6 +44,8 @@ class CategoryPlaylistsNotifier extends FamilyPaginatedAsyncNotifier<
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
build(arg) async {
|
build(arg) async {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
ref.watch(spotifyProvider);
|
ref.watch(spotifyProvider);
|
||||||
ref.watch(userPreferencesProvider.select((s) => s.locale));
|
ref.watch(userPreferencesProvider.select((s) => s.locale));
|
||||||
ref.watch(userPreferencesProvider.select((s) => s.recommendationMarket));
|
ref.watch(userPreferencesProvider.select((s) => s.recommendationMarket));
|
||||||
@ -59,7 +61,7 @@ class CategoryPlaylistsNotifier extends FamilyPaginatedAsyncNotifier<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final categoryPlaylistsProvider = AsyncNotifierProviderFamily<
|
final categoryPlaylistsProvider = AutoDisposeAsyncNotifierProviderFamily<
|
||||||
CategoryPlaylistsNotifier, CategoryPlaylistsState, String>(
|
CategoryPlaylistsNotifier, CategoryPlaylistsState, String>(
|
||||||
() => CategoryPlaylistsNotifier(),
|
() => CategoryPlaylistsNotifier(),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -85,6 +85,6 @@ class PlaylistNotifier extends FamilyAsyncNotifier<Playlist, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final playlistProvider =
|
final playlistProvider =
|
||||||
AsyncNotifierProviderFamily<PlaylistNotifier, Playlist, String>(
|
AsyncNotifierProvider.family<PlaylistNotifier, Playlist, String>(
|
||||||
() => PlaylistNotifier(),
|
() => PlaylistNotifier(),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -24,8 +24,8 @@ class PlaylistTracksState extends PaginatedState<Track> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlaylistTracksNotifier
|
class PlaylistTracksNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
|
||||||
extends FamilyPaginatedAsyncNotifier<Track, PlaylistTracksState, String> {
|
Track, PlaylistTracksState, String> {
|
||||||
PlaylistTracksNotifier() : super();
|
PlaylistTracksNotifier() : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -34,11 +34,16 @@ class PlaylistTracksNotifier
|
|||||||
.getTracksByPlaylistId(arg)
|
.getTracksByPlaylistId(arg)
|
||||||
.getPage(limit, offset);
|
.getPage(limit, offset);
|
||||||
|
|
||||||
return tracks.items?.toList() ?? <Track>[];
|
/// Filter out tracks with null id because some personal playlists
|
||||||
|
/// may contain local tracks that are not available in the Spotify catalog
|
||||||
|
return tracks.items?.where((track) => track.id != null).toList() ??
|
||||||
|
<Track>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
build(arg) async {
|
build(arg) async {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
ref.watch(spotifyProvider);
|
ref.watch(spotifyProvider);
|
||||||
final tracks = await fetch(arg, 0, 20);
|
final tracks = await fetch(arg, 0, 20);
|
||||||
|
|
||||||
@ -51,7 +56,7 @@ class PlaylistTracksNotifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final playlistTracksProvider = AsyncNotifierProviderFamily<
|
final playlistTracksProvider = AutoDisposeAsyncNotifierProviderFamily<
|
||||||
PlaylistTracksNotifier, PlaylistTracksState, String>(
|
PlaylistTracksNotifier, PlaylistTracksState, String>(
|
||||||
() => PlaylistTracksNotifier(),
|
() => PlaylistTracksNotifier(),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
final searchTermStateProvider = StateProvider<String>((ref) => "");
|
final searchTermStateProvider = StateProvider.autoDispose<String>(
|
||||||
|
(ref) {
|
||||||
|
ref.cacheFor(const Duration(minutes: 2));
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
class SearchState<Y> extends PaginatedState<Y> {
|
class SearchState<Y> extends PaginatedState<Y> {
|
||||||
SearchState({
|
SearchState({
|
||||||
@ -26,8 +31,8 @@ class SearchState<Y> extends PaginatedState<Y> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SearchNotifier<Y>
|
class SearchNotifier<Y> extends AutoDisposeFamilyPaginatedAsyncNotifier<Y,
|
||||||
extends FamilyPaginatedAsyncNotifier<Y, SearchState<Y>, SearchType> {
|
SearchState<Y>, SearchType> {
|
||||||
SearchNotifier() : super();
|
SearchNotifier() : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -46,6 +51,8 @@ class SearchNotifier<Y>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
build(arg) async {
|
build(arg) async {
|
||||||
|
ref.cacheFor(const Duration(minutes: 2));
|
||||||
|
|
||||||
ref.watch(searchTermStateProvider);
|
ref.watch(searchTermStateProvider);
|
||||||
ref.watch(spotifyProvider);
|
ref.watch(spotifyProvider);
|
||||||
ref.watch(
|
ref.watch(
|
||||||
@ -63,7 +70,7 @@ class SearchNotifier<Y>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final searchProvider =
|
final searchProvider = AsyncNotifierProvider.autoDispose
|
||||||
AsyncNotifierProvider.family<SearchNotifier, SearchState, SearchType>(
|
.family<SearchNotifier, SearchState, SearchType>(
|
||||||
() => SearchNotifier(),
|
() => SearchNotifier(),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -66,3 +66,8 @@ part 'utils/state.dart';
|
|||||||
part 'utils/provider.dart';
|
part 'utils/provider.dart';
|
||||||
part 'utils/persistence.dart';
|
part 'utils/persistence.dart';
|
||||||
part 'utils/async.dart';
|
part 'utils/async.dart';
|
||||||
|
|
||||||
|
part 'utils/provider/paginated.dart';
|
||||||
|
part 'utils/provider/cursor.dart';
|
||||||
|
part 'utils/provider/paginated_family.dart';
|
||||||
|
part 'utils/provider/cursor_family.dart';
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
final trackProvider = FutureProvider.family<Track, String>((ref, id) async {
|
final trackProvider =
|
||||||
|
FutureProvider.autoDispose.family<Track, String>((ref, id) async {
|
||||||
|
ref.cacheFor();
|
||||||
|
|
||||||
final spotify = ref.watch(spotifyProvider);
|
final spotify = ref.watch(spotifyProvider);
|
||||||
|
|
||||||
return spotify.tracks.get(id);
|
return spotify.tracks.get(id);
|
||||||
|
|||||||
@ -1,6 +1,24 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
// ignore: invalid_use_of_internal_member
|
// ignore: invalid_use_of_internal_member
|
||||||
mixin SpotifyMixin<T> on BuildlessAsyncNotifier<T> {
|
mixin SpotifyMixin<T> on AsyncNotifierBase<T> {
|
||||||
SpotifyApi get spotify => ref.read(spotifyProvider);
|
SpotifyApi get spotify => ref.read(spotifyProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension on AutoDisposeAsyncNotifierProviderRef {
|
||||||
|
// When invoked keeps your provider alive for [duration]
|
||||||
|
void cacheFor([Duration duration = const Duration(minutes: 5)]) {
|
||||||
|
final link = keepAlive();
|
||||||
|
final timer = Timer(duration, () => link.close());
|
||||||
|
onDispose(() => timer.cancel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on AutoDisposeRef {
|
||||||
|
// When invoked keeps your provider alive for [duration]
|
||||||
|
void cacheFor([Duration duration = const Duration(minutes: 5)]) {
|
||||||
|
final link = keepAlive();
|
||||||
|
final timer = Timer(duration, () => link.close());
|
||||||
|
onDispose(() => timer.cancel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,214 +4,3 @@ part of '../spotify.dart';
|
|||||||
class AsyncLoadingNext<T> extends AsyncData<T> {
|
class AsyncLoadingNext<T> extends AsyncData<T> {
|
||||||
const AsyncLoadingNext(super.value);
|
const AsyncLoadingNext(super.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class PaginatedAsyncNotifier<K, T extends BasePaginatedState<K, int>>
|
|
||||||
extends AsyncNotifier<T> with SpotifyMixin<T> {
|
|
||||||
Future<List<K>> fetch(int offset, int limit);
|
|
||||||
|
|
||||||
Future<void> fetchMore() async {
|
|
||||||
if (state.value == null || !state.value!.hasMore) return;
|
|
||||||
|
|
||||||
state = AsyncLoadingNext(state.asData!.value);
|
|
||||||
|
|
||||||
state = await AsyncValue.guard(
|
|
||||||
() async {
|
|
||||||
final items = await fetch(
|
|
||||||
state.value!.offset + state.value!.limit,
|
|
||||||
state.value!.limit,
|
|
||||||
);
|
|
||||||
return state.value!.copyWith(
|
|
||||||
hasMore: items.length == state.value!.limit,
|
|
||||||
items: [
|
|
||||||
...state.value!.items,
|
|
||||||
...items,
|
|
||||||
],
|
|
||||||
offset: state.value!.offset + state.value!.limit,
|
|
||||||
) as T;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<K>> fetchAll() async {
|
|
||||||
if (state.value == null) return [];
|
|
||||||
if (!state.value!.hasMore) return state.value!.items;
|
|
||||||
|
|
||||||
bool hasMore = true;
|
|
||||||
while (hasMore) {
|
|
||||||
await update((state) async {
|
|
||||||
final items = await fetch(
|
|
||||||
state.offset + state.limit,
|
|
||||||
state.limit,
|
|
||||||
);
|
|
||||||
|
|
||||||
hasMore = items.length == state.limit;
|
|
||||||
return state.copyWith(
|
|
||||||
items: [...state.items, ...items],
|
|
||||||
offset: state.offset + state.limit,
|
|
||||||
hasMore: hasMore,
|
|
||||||
) as T;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.value!.items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class CursorPaginatedAsyncNotifier<K,
|
|
||||||
T extends CursorPaginatedState<K>> extends AsyncNotifier<T>
|
|
||||||
with SpotifyMixin<T> {
|
|
||||||
Future<(List<K> items, String nextCursor)> fetch(String? offset, int limit);
|
|
||||||
|
|
||||||
Future<void> fetchMore() async {
|
|
||||||
if (state.value == null || !state.value!.hasMore) return;
|
|
||||||
|
|
||||||
state = AsyncLoadingNext(state.asData!.value);
|
|
||||||
|
|
||||||
state = await AsyncValue.guard(
|
|
||||||
() async {
|
|
||||||
final items = await fetch(state.value!.offset, state.value!.limit);
|
|
||||||
return state.value!.copyWith(
|
|
||||||
hasMore: items.$1.length == state.value!.limit,
|
|
||||||
items: [
|
|
||||||
...state.value!.items,
|
|
||||||
...items.$1,
|
|
||||||
],
|
|
||||||
offset: items.$2,
|
|
||||||
) as T;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<K>> fetchAll() async {
|
|
||||||
if (state.value == null) return [];
|
|
||||||
if (!state.value!.hasMore) return state.value!.items;
|
|
||||||
|
|
||||||
bool hasMore = true;
|
|
||||||
while (hasMore) {
|
|
||||||
await update((state) async {
|
|
||||||
final items = await fetch(state.offset, state.limit);
|
|
||||||
|
|
||||||
hasMore = items.$1.length == state.limit;
|
|
||||||
return state.copyWith(
|
|
||||||
items: [...state.items, ...items.$1],
|
|
||||||
offset: items.$2,
|
|
||||||
hasMore: hasMore,
|
|
||||||
) as T;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.value!.items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class FamilyPaginatedAsyncNotifier<
|
|
||||||
K,
|
|
||||||
T extends BasePaginatedState<K, dynamic>,
|
|
||||||
A> extends FamilyAsyncNotifier<T, A> with SpotifyMixin<T> {
|
|
||||||
Future<List<K>> fetch(A arg, int offset, int limit);
|
|
||||||
|
|
||||||
Future<void> fetchMore() async {
|
|
||||||
if (state.value == null || !state.value!.hasMore) return;
|
|
||||||
|
|
||||||
state = AsyncLoadingNext(state.asData!.value);
|
|
||||||
|
|
||||||
state = await AsyncValue.guard(
|
|
||||||
() async {
|
|
||||||
final items = await fetch(
|
|
||||||
arg,
|
|
||||||
state.value!.offset + state.value!.limit,
|
|
||||||
state.value!.limit,
|
|
||||||
);
|
|
||||||
return state.value!.copyWith(
|
|
||||||
hasMore: items.length == state.value!.limit,
|
|
||||||
items: [
|
|
||||||
...state.value!.items,
|
|
||||||
...items,
|
|
||||||
],
|
|
||||||
offset: state.value!.offset + state.value!.limit,
|
|
||||||
) as T;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<K>> fetchAll() async {
|
|
||||||
if (state.value == null) return [];
|
|
||||||
if (!state.value!.hasMore) return state.value!.items;
|
|
||||||
|
|
||||||
bool hasMore = true;
|
|
||||||
while (hasMore) {
|
|
||||||
await update((state) async {
|
|
||||||
final items = await fetch(
|
|
||||||
arg,
|
|
||||||
state.offset + state.limit,
|
|
||||||
state.limit,
|
|
||||||
);
|
|
||||||
|
|
||||||
hasMore = items.length == state.limit;
|
|
||||||
return state.copyWith(
|
|
||||||
items: [...state.items, ...items],
|
|
||||||
offset: state.offset + state.limit,
|
|
||||||
hasMore: hasMore,
|
|
||||||
) as T;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.value!.items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class FamilyCursorPaginatedAsyncNotifier<
|
|
||||||
K,
|
|
||||||
T extends CursorPaginatedState<K>,
|
|
||||||
A> extends FamilyAsyncNotifier<T, A> with SpotifyMixin<T> {
|
|
||||||
Future<(List<K> items, String nextCursor)> fetch(
|
|
||||||
A arg,
|
|
||||||
String? offset,
|
|
||||||
int limit,
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<void> fetchMore() async {
|
|
||||||
if (state.value == null || !state.value!.hasMore) return;
|
|
||||||
|
|
||||||
state = AsyncLoadingNext(state.asData!.value);
|
|
||||||
|
|
||||||
state = await AsyncValue.guard(
|
|
||||||
() async {
|
|
||||||
final items = await fetch(arg, state.value!.offset, state.value!.limit);
|
|
||||||
return state.value!.copyWith(
|
|
||||||
hasMore: items.$1.length == state.value!.limit,
|
|
||||||
items: [
|
|
||||||
...state.value!.items,
|
|
||||||
...items.$1,
|
|
||||||
],
|
|
||||||
offset: items.$2,
|
|
||||||
) as T;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<K>> fetchAll() async {
|
|
||||||
if (state.value == null) return [];
|
|
||||||
if (!state.value!.hasMore) return state.value!.items;
|
|
||||||
|
|
||||||
bool hasMore = true;
|
|
||||||
while (hasMore) {
|
|
||||||
await update((state) async {
|
|
||||||
final items = await fetch(
|
|
||||||
arg,
|
|
||||||
state.offset,
|
|
||||||
state.limit,
|
|
||||||
);
|
|
||||||
|
|
||||||
hasMore = items.$1.length == state.limit;
|
|
||||||
return state.copyWith(
|
|
||||||
items: [...state.items, ...items.$1],
|
|
||||||
offset: items.$2,
|
|
||||||
hasMore: hasMore,
|
|
||||||
) as T;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.value!.items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
56
lib/provider/spotify/utils/provider/cursor.dart
Normal file
56
lib/provider/spotify/utils/provider/cursor.dart
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
part of '../../spotify.dart';
|
||||||
|
|
||||||
|
mixin CursorPaginatedAsyncNotifierMixin<K, T extends CursorPaginatedState<K>>
|
||||||
|
// ignore: invalid_use_of_internal_member
|
||||||
|
on AsyncNotifierBase<T> {
|
||||||
|
Future<(List<K> items, String nextCursor)> fetch(String? offset, int limit);
|
||||||
|
|
||||||
|
Future<void> fetchMore() async {
|
||||||
|
if (state.value == null || !state.value!.hasMore) return;
|
||||||
|
|
||||||
|
state = AsyncLoadingNext(state.asData!.value);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(
|
||||||
|
() async {
|
||||||
|
final items = await fetch(state.value!.offset, state.value!.limit);
|
||||||
|
return state.value!.copyWith(
|
||||||
|
hasMore: items.$1.length == state.value!.limit,
|
||||||
|
items: [
|
||||||
|
...state.value!.items,
|
||||||
|
...items.$1,
|
||||||
|
],
|
||||||
|
offset: items.$2,
|
||||||
|
) as T;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<K>> fetchAll() async {
|
||||||
|
if (state.value == null) return [];
|
||||||
|
if (!state.value!.hasMore) return state.value!.items;
|
||||||
|
|
||||||
|
bool hasMore = true;
|
||||||
|
while (hasMore) {
|
||||||
|
await update((state) async {
|
||||||
|
final items = await fetch(state.offset, state.limit);
|
||||||
|
|
||||||
|
hasMore = items.$1.length == state.limit;
|
||||||
|
return state.copyWith(
|
||||||
|
items: [...state.items, ...items.$1],
|
||||||
|
offset: items.$2,
|
||||||
|
hasMore: hasMore,
|
||||||
|
) as T;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.value!.items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CursorPaginatedAsyncNotifier<K,
|
||||||
|
T extends CursorPaginatedState<K>> extends AsyncNotifier<T>
|
||||||
|
with CursorPaginatedAsyncNotifierMixin<K, T>, SpotifyMixin<T> {}
|
||||||
|
|
||||||
|
abstract class AutoDisposeCursorPaginatedAsyncNotifier<K,
|
||||||
|
T extends CursorPaginatedState<K>> extends AutoDisposeAsyncNotifier<T>
|
||||||
|
with CursorPaginatedAsyncNotifierMixin<K, T>, SpotifyMixin<T> {}
|
||||||
113
lib/provider/spotify/utils/provider/cursor_family.dart
Normal file
113
lib/provider/spotify/utils/provider/cursor_family.dart
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
part of '../../spotify.dart';
|
||||||
|
|
||||||
|
abstract class FamilyCursorPaginatedAsyncNotifier<
|
||||||
|
K,
|
||||||
|
T extends CursorPaginatedState<K>,
|
||||||
|
A> extends FamilyAsyncNotifier<T, A> with SpotifyMixin<T> {
|
||||||
|
Future<(List<K> items, String nextCursor)> fetch(
|
||||||
|
A arg,
|
||||||
|
String? offset,
|
||||||
|
int limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> fetchMore() async {
|
||||||
|
if (state.value == null || !state.value!.hasMore) return;
|
||||||
|
|
||||||
|
state = AsyncLoadingNext(state.asData!.value);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(
|
||||||
|
() async {
|
||||||
|
final items = await fetch(arg, state.value!.offset, state.value!.limit);
|
||||||
|
return state.value!.copyWith(
|
||||||
|
hasMore: items.$1.length == state.value!.limit,
|
||||||
|
items: [
|
||||||
|
...state.value!.items,
|
||||||
|
...items.$1,
|
||||||
|
],
|
||||||
|
offset: items.$2,
|
||||||
|
) as T;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<K>> fetchAll() async {
|
||||||
|
if (state.value == null) return [];
|
||||||
|
if (!state.value!.hasMore) return state.value!.items;
|
||||||
|
|
||||||
|
bool hasMore = true;
|
||||||
|
while (hasMore) {
|
||||||
|
await update((state) async {
|
||||||
|
final items = await fetch(
|
||||||
|
arg,
|
||||||
|
state.offset,
|
||||||
|
state.limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
hasMore = items.$1.length == state.limit;
|
||||||
|
return state.copyWith(
|
||||||
|
items: [...state.items, ...items.$1],
|
||||||
|
offset: items.$2,
|
||||||
|
hasMore: hasMore,
|
||||||
|
) as T;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.value!.items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AutoDisposeFamilyCursorPaginatedAsyncNotifier<
|
||||||
|
K,
|
||||||
|
T extends CursorPaginatedState<K>,
|
||||||
|
A> extends AutoDisposeFamilyAsyncNotifier<T, A> with SpotifyMixin<T> {
|
||||||
|
Future<(List<K> items, String nextCursor)> fetch(
|
||||||
|
A arg,
|
||||||
|
String? offset,
|
||||||
|
int limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> fetchMore() async {
|
||||||
|
if (state.value == null || !state.value!.hasMore) return;
|
||||||
|
|
||||||
|
state = AsyncLoadingNext(state.asData!.value);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(
|
||||||
|
() async {
|
||||||
|
final items = await fetch(arg, state.value!.offset, state.value!.limit);
|
||||||
|
return state.value!.copyWith(
|
||||||
|
hasMore: items.$1.length == state.value!.limit,
|
||||||
|
items: [
|
||||||
|
...state.value!.items,
|
||||||
|
...items.$1,
|
||||||
|
],
|
||||||
|
offset: items.$2,
|
||||||
|
) as T;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<K>> fetchAll() async {
|
||||||
|
if (state.value == null) return [];
|
||||||
|
if (!state.value!.hasMore) return state.value!.items;
|
||||||
|
|
||||||
|
bool hasMore = true;
|
||||||
|
while (hasMore) {
|
||||||
|
await update((state) async {
|
||||||
|
final items = await fetch(
|
||||||
|
arg,
|
||||||
|
state.offset,
|
||||||
|
state.limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
hasMore = items.$1.length == state.limit;
|
||||||
|
return state.copyWith(
|
||||||
|
items: [...state.items, ...items.$1],
|
||||||
|
offset: items.$2,
|
||||||
|
hasMore: hasMore,
|
||||||
|
) as T;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.value!.items;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
lib/provider/spotify/utils/provider/paginated.dart
Normal file
63
lib/provider/spotify/utils/provider/paginated.dart
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
part of '../../spotify.dart';
|
||||||
|
|
||||||
|
mixin PaginatedAsyncNotifierMixin<K, T extends BasePaginatedState<K, int>>
|
||||||
|
// ignore: invalid_use_of_internal_member
|
||||||
|
on AsyncNotifierBase<T> {
|
||||||
|
Future<List<K>> fetch(int offset, int limit);
|
||||||
|
|
||||||
|
Future<void> fetchMore() async {
|
||||||
|
if (state.value == null || !state.value!.hasMore) return;
|
||||||
|
|
||||||
|
state = AsyncLoadingNext(state.asData!.value);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(
|
||||||
|
() async {
|
||||||
|
final items = await fetch(
|
||||||
|
state.value!.offset + state.value!.limit,
|
||||||
|
state.value!.limit,
|
||||||
|
);
|
||||||
|
return state.value!.copyWith(
|
||||||
|
hasMore: items.length == state.value!.limit,
|
||||||
|
items: [
|
||||||
|
...state.value!.items,
|
||||||
|
...items,
|
||||||
|
],
|
||||||
|
offset: state.value!.offset + state.value!.limit,
|
||||||
|
) as T;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<K>> fetchAll() async {
|
||||||
|
if (state.value == null) return [];
|
||||||
|
if (!state.value!.hasMore) return state.value!.items;
|
||||||
|
|
||||||
|
bool hasMore = true;
|
||||||
|
while (hasMore) {
|
||||||
|
await update((state) async {
|
||||||
|
final items = await fetch(
|
||||||
|
state.offset + state.limit,
|
||||||
|
state.limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
hasMore = items.length == state.limit;
|
||||||
|
return state.copyWith(
|
||||||
|
items: [...state.items, ...items],
|
||||||
|
offset: state.offset + state.limit,
|
||||||
|
hasMore: hasMore,
|
||||||
|
) as T;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.value!.items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class PaginatedAsyncNotifier<K, T extends BasePaginatedState<K, int>>
|
||||||
|
extends AsyncNotifier<T>
|
||||||
|
with PaginatedAsyncNotifierMixin<K, T>, SpotifyMixin<T> {}
|
||||||
|
|
||||||
|
abstract class AutoDisposePaginatedAsyncNotifier<K,
|
||||||
|
T extends BasePaginatedState<K, int>>
|
||||||
|
extends AutoDisposeAsyncNotifier<T>
|
||||||
|
with PaginatedAsyncNotifierMixin<K, T>, SpotifyMixin<T> {}
|
||||||
113
lib/provider/spotify/utils/provider/paginated_family.dart
Normal file
113
lib/provider/spotify/utils/provider/paginated_family.dart
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
part of '../../spotify.dart';
|
||||||
|
|
||||||
|
abstract class FamilyPaginatedAsyncNotifier<
|
||||||
|
K,
|
||||||
|
T extends BasePaginatedState<K, dynamic>,
|
||||||
|
A> extends FamilyAsyncNotifier<T, A> with SpotifyMixin<T> {
|
||||||
|
Future<List<K>> fetch(A arg, int offset, int limit);
|
||||||
|
|
||||||
|
Future<void> fetchMore() async {
|
||||||
|
if (state.value == null || !state.value!.hasMore) return;
|
||||||
|
|
||||||
|
state = AsyncLoadingNext(state.asData!.value);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(
|
||||||
|
() async {
|
||||||
|
final items = await fetch(
|
||||||
|
arg,
|
||||||
|
state.value!.offset + state.value!.limit,
|
||||||
|
state.value!.limit,
|
||||||
|
);
|
||||||
|
return state.value!.copyWith(
|
||||||
|
hasMore: items.length == state.value!.limit,
|
||||||
|
items: [
|
||||||
|
...state.value!.items,
|
||||||
|
...items,
|
||||||
|
],
|
||||||
|
offset: state.value!.offset + state.value!.limit,
|
||||||
|
) as T;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<K>> fetchAll() async {
|
||||||
|
if (state.value == null) return [];
|
||||||
|
if (!state.value!.hasMore) return state.value!.items;
|
||||||
|
|
||||||
|
bool hasMore = true;
|
||||||
|
while (hasMore) {
|
||||||
|
await update((state) async {
|
||||||
|
final items = await fetch(
|
||||||
|
arg,
|
||||||
|
state.offset + state.limit,
|
||||||
|
state.limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
hasMore = items.length == state.limit;
|
||||||
|
return state.copyWith(
|
||||||
|
items: [...state.items, ...items],
|
||||||
|
offset: state.offset + state.limit,
|
||||||
|
hasMore: hasMore,
|
||||||
|
) as T;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.value!.items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AutoDisposeFamilyPaginatedAsyncNotifier<
|
||||||
|
K,
|
||||||
|
T extends BasePaginatedState<K, dynamic>,
|
||||||
|
A> extends AutoDisposeFamilyAsyncNotifier<T, A> with SpotifyMixin<T> {
|
||||||
|
Future<List<K>> fetch(A arg, int offset, int limit);
|
||||||
|
|
||||||
|
Future<void> fetchMore() async {
|
||||||
|
if (state.value == null || !state.value!.hasMore) return;
|
||||||
|
|
||||||
|
state = AsyncLoadingNext(state.asData!.value);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(
|
||||||
|
() async {
|
||||||
|
final items = await fetch(
|
||||||
|
arg,
|
||||||
|
state.value!.offset + state.value!.limit,
|
||||||
|
state.value!.limit,
|
||||||
|
);
|
||||||
|
return state.value!.copyWith(
|
||||||
|
hasMore: items.length == state.value!.limit,
|
||||||
|
items: [
|
||||||
|
...state.value!.items,
|
||||||
|
...items,
|
||||||
|
],
|
||||||
|
offset: state.value!.offset + state.value!.limit,
|
||||||
|
) as T;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<K>> fetchAll() async {
|
||||||
|
if (state.value == null) return [];
|
||||||
|
if (!state.value!.hasMore) return state.value!.items;
|
||||||
|
|
||||||
|
bool hasMore = true;
|
||||||
|
while (hasMore) {
|
||||||
|
await update((state) async {
|
||||||
|
final items = await fetch(
|
||||||
|
arg,
|
||||||
|
state.offset + state.limit,
|
||||||
|
state.limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
hasMore = items.length == state.limit;
|
||||||
|
return state.copyWith(
|
||||||
|
items: [...state.items, ...items],
|
||||||
|
offset: state.offset + state.limit,
|
||||||
|
hasMore: hasMore,
|
||||||
|
) as T;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.value!.items;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user