import 'dart:collection'; import 'package:result_monad/result_monad.dart'; import '../models/exec_error.dart'; import 'paged_response.dart'; import 'paging_data.dart'; class PagesManager { final _pages = >>[]; final List Function(TResult) idMapper; final FutureResult, ExecError> Function(PagingData) onRequest; PagesManager({ required this.idMapper, required this.onRequest, }); UnmodifiableListView get pages => UnmodifiableListView(_pages); void clear() { _pages.clear(); } Result>, ExecError> pageFromId(TID id) { for (final p in _pages) { if (p.data.contains(id)) { return Result.ok(p); } } return buildErrorResult( type: ErrorType.notFound, message: 'ID $id not in any page'); } FutureResult, ExecError> initialize(int limit) async { if (_pages.isNotEmpty) { return buildErrorResult( type: ErrorType.rangeError, message: 'Cannot initialize a loaded manager'); } final result = await onRequest(PagingData(limit: limit)); if (result.isSuccess) { if (result.value.previous != null || result.value.next != null) { final newPage = result.value.map((data) => idMapper(data)); _pages.add(newPage); } } return result; } FutureResult, ExecError> nextWithPage( PagedResponse> currentPage) async { return _previousOrNext(currentPage.id, false); } FutureResult, ExecError> previousWithPage( PagedResponse> currentPage) async { return _previousOrNext(currentPage.id, true); } FutureResult, ExecError> nextWithResult( PagedResponse currentPage) async { return _previousOrNext(currentPage.id, false); } FutureResult, ExecError> previousWithResult( PagedResponse currentPage) async { return _previousOrNext(currentPage.id, true); } FutureResult, ExecError> nextFromEnd() async { if (_pages.isEmpty) { return buildErrorResult(type: ErrorType.rangeError); } return _previousOrNext(_pages.last.id, false); } FutureResult, ExecError> previousFromBeginning() async { if (_pages.isEmpty) { return buildErrorResult(type: ErrorType.rangeError); } return _previousOrNext(_pages.first.id, true); } FutureResult, ExecError> _previousOrNext( String id, bool asPrevious) async { final currentIndex = _pages.indexWhere((p) => p.id == id); if (currentIndex < 0) { return buildErrorResult( type: ErrorType.notFound, message: 'Passed in page is not part of this manager', ); } final currentPage = _pages[currentIndex]; final newPagingData = asPrevious ? currentPage.previous : currentPage.next; if (newPagingData == null) { return buildErrorResult( type: ErrorType.rangeError, message: asPrevious ? 'No previous page' : 'No next page', ); } final result = await onRequest(newPagingData); if (result.isSuccess && result.value.hasMorePages) { final newPage = result.value.map((data) => idMapper(data)); if (asPrevious) { _pages.insert(currentIndex, newPage); } else { _pages.insert(currentIndex + 1, newPage); } } return result; } }