import 'dart:async'; import 'package:hooks_riverpod/hooks_riverpod.dart'; abstract class PaginationController { int? get totalCount; int get fetchedCount; bool get fetchedAll; FutureOr> fetch(); Future refresh(); Future fetchFurther(); } abstract class PaginationFiltered { late F currentFilter; Future applyFilter(F filter); } mixin AsyncPaginationController on AsyncNotifier> implements PaginationController { @override int? totalCount; @override int get fetchedCount => state.value?.length ?? 0; @override bool get fetchedAll => totalCount != null && fetchedCount >= totalCount!; @override FutureOr> build() async => fetch(); @override Future refresh() async { totalCount = null; state = AsyncData>([]); final newState = await AsyncValue.guard>(() async { return await fetch(); }); state = newState; } @override Future fetchFurther() async { if (fetchedAll) return; state = AsyncLoading>(); final newState = await AsyncValue.guard>(() async { final elements = await fetch(); return [...?state.value, ...elements]; }); state = newState; } } mixin AsyncPaginationFilter on AsyncPaginationController implements PaginationFiltered { @override Future applyFilter(F filter) async { if (currentFilter == filter) return; // Reset the data totalCount = null; state = AsyncData>([]); currentFilter = filter; final newState = await AsyncValue.guard>(() async { return await fetch(); }); state = newState; } }