import 'dart:async'; import 'dart:math'; 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'; import 'package:spotube/services/logger/logger.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; final oldState = state.value; try { state = AsyncLoadingNext(state.asData!.value); 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(); state = AsyncData(newState.copyWith(items: [...oldItems, ...items])); } catch (e, stack) { AppLogger.reportError(e, stack); state = AsyncData(oldState!); } } Future> fetchAll() async { if (state.value == null) return []; if (!state.value!.hasMore) return state.value!.items.cast(); bool hasMore = true; while (hasMore) { final newState = await fetch( state.value!.nextOffset!, max(state.value!.limit, 100), ) .catchError( (e) => fetch(state.value!.nextOffset!, max(state.value!.limit, 50)), ) .catchError( (e) => fetch(state.value!.nextOffset!, state.value!.limit), ) .catchError( (e) async { await Future.delayed(const Duration(milliseconds: 500)); return fetch(state.value!.nextOffset!, state.value!.limit); }, ); hasMore = newState.hasMore; final oldItems = state.value!.items.isEmpty ? [] : state.value!.items.cast(); final items = newState.items.isEmpty ? [] : newState.items.cast(); state = AsyncData( 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 {}