import 'dart:async'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/models/metadata/metadata.dart'; // ignore: implementation_imports import 'package:riverpod/src/async_notifier.dart'; import 'package:spotube/provider/metadata_plugin/utils/common.dart'; mixin PaginatedAsyncNotifierMixin // ignore: invalid_use_of_internal_member on AsyncNotifierBase> { Future> fetch(int offset, int limit); Future fetchMore() async { if (state.value == null || !state.value!.hasMore) return; state = AsyncLoadingNext(state.asData!.value); state = await AsyncValue.guard( () async { final newState = await fetch( state.value!.nextOffset!, state.value!.limit, ); final oldItems = state.value!.items.isEmpty ? [] : state.value!.items.cast(); final items = newState.items.isEmpty ? [] : newState.items.cast(); return newState.copyWith(items: [...oldItems, ...items]); }, ); } Future> fetchAll() async { if (state.value == null) return []; if (!state.value!.hasMore) return state.value!.items.cast(); bool hasMore = true; while (hasMore) { await update((state) async { final newState = await fetch( state.nextOffset!, state.limit, ); hasMore = newState.hasMore; final oldItems = state.items.isEmpty ? [] : state.items.cast(); final items = newState.items.isEmpty ? [] : newState.items.cast(); return newState.copyWith(items: [...oldItems, ...items]); }); } return state.value!.items.cast(); } } abstract class PaginatedAsyncNotifier extends AsyncNotifier> with PaginatedAsyncNotifierMixin, MetadataPluginMixin {} abstract class AutoDisposePaginatedAsyncNotifier extends AutoDisposeAsyncNotifier> with PaginatedAsyncNotifierMixin, MetadataPluginMixin {}