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
|
||||
Widget build(BuildContext context, ref) {
|
||||
final theme = Theme.of(context);
|
||||
final controller = useTextEditingController();
|
||||
final searchTerm = ref.watch(searchTermStateProvider);
|
||||
final controller = useTextEditingController(text: searchTerm);
|
||||
|
||||
ref.watch(AuthenticationNotifier.provider);
|
||||
final authenticationNotifier =
|
||||
ref.watch(AuthenticationNotifier.provider.notifier);
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
|
||||
final searchTerm = ref.watch(searchTermStateProvider);
|
||||
|
||||
final searchTrack = ref.watch(searchProvider(SearchType.track));
|
||||
final searchAlbum = ref.watch(searchProvider(SearchType.album));
|
||||
final searchPlaylist = ref.watch(searchProvider(SearchType.playlist));
|
||||
|
||||
@ -24,8 +24,8 @@ class AlbumTracksState extends PaginatedState<Track> {
|
||||
}
|
||||
}
|
||||
|
||||
class AlbumTracksNotifier
|
||||
extends FamilyPaginatedAsyncNotifier<Track, AlbumTracksState, AlbumSimple> {
|
||||
class AlbumTracksNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<Track,
|
||||
AlbumTracksState, AlbumSimple> {
|
||||
AlbumTracksNotifier() : super();
|
||||
|
||||
@override
|
||||
@ -39,6 +39,8 @@ class AlbumTracksNotifier
|
||||
|
||||
@override
|
||||
build(arg) async {
|
||||
ref.cacheFor();
|
||||
|
||||
ref.watch(spotifyProvider);
|
||||
final tracks = await fetch(arg, 0, 20);
|
||||
return AlbumTracksState(
|
||||
@ -50,7 +52,7 @@ class AlbumTracksNotifier
|
||||
}
|
||||
}
|
||||
|
||||
final albumTracksProvider = AsyncNotifierProviderFamily<AlbumTracksNotifier,
|
||||
AlbumTracksState, AlbumSimple>(
|
||||
final albumTracksProvider = AutoDisposeAsyncNotifierProviderFamily<
|
||||
AlbumTracksNotifier, AlbumTracksState, AlbumSimple>(
|
||||
() => AlbumTracksNotifier(),
|
||||
);
|
||||
|
||||
@ -24,8 +24,8 @@ class ArtistAlbumsState extends PaginatedState<Album> {
|
||||
}
|
||||
}
|
||||
|
||||
class ArtistAlbumsNotifier
|
||||
extends FamilyPaginatedAsyncNotifier<Album, ArtistAlbumsState, String> {
|
||||
class ArtistAlbumsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
|
||||
Album, ArtistAlbumsState, String> {
|
||||
ArtistAlbumsNotifier() : super();
|
||||
|
||||
@override
|
||||
@ -40,6 +40,8 @@ class ArtistAlbumsNotifier
|
||||
|
||||
@override
|
||||
build(arg) async {
|
||||
ref.cacheFor();
|
||||
|
||||
ref.watch(spotifyProvider);
|
||||
ref.watch(
|
||||
userPreferencesProvider.select((s) => s.recommendationMarket),
|
||||
@ -54,7 +56,7 @@ class ArtistAlbumsNotifier
|
||||
}
|
||||
}
|
||||
|
||||
final artistAlbumsProvider = AsyncNotifierProviderFamily<ArtistAlbumsNotifier,
|
||||
ArtistAlbumsState, String>(
|
||||
final artistAlbumsProvider = AutoDisposeAsyncNotifierProviderFamily<
|
||||
ArtistAlbumsNotifier, ArtistAlbumsState, String>(
|
||||
() => ArtistAlbumsNotifier(),
|
||||
);
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
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);
|
||||
|
||||
return spotify.artists.get(artistId);
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
final relatedArtistsProvider =
|
||||
FutureProvider.family<List<Artist>, String>((ref, artistId) async {
|
||||
final relatedArtistsProvider = FutureProvider.autoDispose
|
||||
.family<List<Artist>, String>((ref, artistId) async {
|
||||
ref.cacheFor();
|
||||
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
final artists = await spotify.artists.relatedArtists(artistId);
|
||||
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
final artistTopTracksProvider = FutureProviderFamily<List<Track>, String>(
|
||||
final artistTopTracksProvider =
|
||||
FutureProvider.autoDispose.family<List<Track>, String>(
|
||||
(ref, artistId) async {
|
||||
ref.cacheFor();
|
||||
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
final market = ref
|
||||
.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> {
|
||||
CategoryPlaylistsNotifier() : super();
|
||||
|
||||
@ -44,6 +44,8 @@ class CategoryPlaylistsNotifier extends FamilyPaginatedAsyncNotifier<
|
||||
|
||||
@override
|
||||
build(arg) async {
|
||||
ref.cacheFor();
|
||||
|
||||
ref.watch(spotifyProvider);
|
||||
ref.watch(userPreferencesProvider.select((s) => s.locale));
|
||||
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(),
|
||||
);
|
||||
|
||||
@ -85,6 +85,6 @@ class PlaylistNotifier extends FamilyAsyncNotifier<Playlist, String> {
|
||||
}
|
||||
|
||||
final playlistProvider =
|
||||
AsyncNotifierProviderFamily<PlaylistNotifier, Playlist, String>(
|
||||
AsyncNotifierProvider.family<PlaylistNotifier, Playlist, String>(
|
||||
() => PlaylistNotifier(),
|
||||
);
|
||||
|
||||
@ -24,8 +24,8 @@ class PlaylistTracksState extends PaginatedState<Track> {
|
||||
}
|
||||
}
|
||||
|
||||
class PlaylistTracksNotifier
|
||||
extends FamilyPaginatedAsyncNotifier<Track, PlaylistTracksState, String> {
|
||||
class PlaylistTracksNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
|
||||
Track, PlaylistTracksState, String> {
|
||||
PlaylistTracksNotifier() : super();
|
||||
|
||||
@override
|
||||
@ -34,11 +34,16 @@ class PlaylistTracksNotifier
|
||||
.getTracksByPlaylistId(arg)
|
||||
.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
|
||||
build(arg) async {
|
||||
ref.cacheFor();
|
||||
|
||||
ref.watch(spotifyProvider);
|
||||
final tracks = await fetch(arg, 0, 20);
|
||||
|
||||
@ -51,7 +56,7 @@ class PlaylistTracksNotifier
|
||||
}
|
||||
}
|
||||
|
||||
final playlistTracksProvider = AsyncNotifierProviderFamily<
|
||||
final playlistTracksProvider = AutoDisposeAsyncNotifierProviderFamily<
|
||||
PlaylistTracksNotifier, PlaylistTracksState, String>(
|
||||
() => PlaylistTracksNotifier(),
|
||||
);
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
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> {
|
||||
SearchState({
|
||||
@ -26,8 +31,8 @@ class SearchState<Y> extends PaginatedState<Y> {
|
||||
}
|
||||
}
|
||||
|
||||
class SearchNotifier<Y>
|
||||
extends FamilyPaginatedAsyncNotifier<Y, SearchState<Y>, SearchType> {
|
||||
class SearchNotifier<Y> extends AutoDisposeFamilyPaginatedAsyncNotifier<Y,
|
||||
SearchState<Y>, SearchType> {
|
||||
SearchNotifier() : super();
|
||||
|
||||
@override
|
||||
@ -46,6 +51,8 @@ class SearchNotifier<Y>
|
||||
|
||||
@override
|
||||
build(arg) async {
|
||||
ref.cacheFor(const Duration(minutes: 2));
|
||||
|
||||
ref.watch(searchTermStateProvider);
|
||||
ref.watch(spotifyProvider);
|
||||
ref.watch(
|
||||
@ -63,7 +70,7 @@ class SearchNotifier<Y>
|
||||
}
|
||||
}
|
||||
|
||||
final searchProvider =
|
||||
AsyncNotifierProvider.family<SearchNotifier, SearchState, SearchType>(
|
||||
final searchProvider = AsyncNotifierProvider.autoDispose
|
||||
.family<SearchNotifier, SearchState, SearchType>(
|
||||
() => SearchNotifier(),
|
||||
);
|
||||
|
||||
@ -66,3 +66,8 @@ part 'utils/state.dart';
|
||||
part 'utils/provider.dart';
|
||||
part 'utils/persistence.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';
|
||||
|
||||
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);
|
||||
|
||||
return spotify.tracks.get(id);
|
||||
|
||||
@ -1,6 +1,24 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
// ignore: invalid_use_of_internal_member
|
||||
mixin SpotifyMixin<T> on BuildlessAsyncNotifier<T> {
|
||||
mixin SpotifyMixin<T> on AsyncNotifierBase<T> {
|
||||
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> {
|
||||
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