mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-19 23:23:32 +00:00
117 lines
3.5 KiB
Dart
117 lines
3.5 KiB
Dart
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<TResult, TID> {
|
|
final _pages = <PagedResponse<List<TID>>>[];
|
|
final List<TID> Function(TResult) idMapper;
|
|
final FutureResult<PagedResponse<TResult>, ExecError> Function(PagingData)
|
|
onRequest;
|
|
|
|
PagesManager({
|
|
required this.idMapper,
|
|
required this.onRequest,
|
|
});
|
|
|
|
UnmodifiableListView<PagedResponse> get pages => UnmodifiableListView(_pages);
|
|
|
|
void clear() {
|
|
_pages.clear();
|
|
}
|
|
|
|
Result<PagedResponse<List<TID>>, 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<PagedResponse<TResult>, 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<PagedResponse<TResult>, ExecError> nextWithPage(
|
|
PagedResponse<List<TID>> currentPage) async {
|
|
return _previousOrNext(currentPage.id, false);
|
|
}
|
|
|
|
FutureResult<PagedResponse<TResult>, ExecError> previousWithPage(
|
|
PagedResponse<List<TID>> currentPage) async {
|
|
return _previousOrNext(currentPage.id, true);
|
|
}
|
|
|
|
FutureResult<PagedResponse<TResult>, ExecError> nextWithResult(
|
|
PagedResponse<TResult> currentPage) async {
|
|
return _previousOrNext(currentPage.id, false);
|
|
}
|
|
|
|
FutureResult<PagedResponse<TResult>, ExecError> previousWithResult(
|
|
PagedResponse<TResult> currentPage) async {
|
|
return _previousOrNext(currentPage.id, true);
|
|
}
|
|
|
|
FutureResult<PagedResponse<TResult>, ExecError> nextFromEnd() async {
|
|
if (_pages.isEmpty) {
|
|
return buildErrorResult(type: ErrorType.rangeError);
|
|
}
|
|
return _previousOrNext(_pages.last.id, false);
|
|
}
|
|
|
|
FutureResult<PagedResponse<TResult>, ExecError>
|
|
previousFromBeginning() async {
|
|
if (_pages.isEmpty) {
|
|
return buildErrorResult(type: ErrorType.rangeError);
|
|
}
|
|
return _previousOrNext(_pages.first.id, true);
|
|
}
|
|
|
|
FutureResult<PagedResponse<TResult>, 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;
|
|
}
|
|
}
|