kopia lustrzana https://gitlab.com/mysocialportal/relatica
124 wiersze
3.6 KiB
Dart
124 wiersze
3.6 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<bool>>[];
|
|
final List<TID> Function(TResult) idMapper;
|
|
final FutureResult<PagedResponse<TResult>, ExecError> Function(PagingData)
|
|
onRequest;
|
|
|
|
PagesManager({
|
|
required this.idMapper,
|
|
required this.onRequest,
|
|
List<PagedResponse>? initialPages,
|
|
}) {
|
|
if (initialPages == null) {
|
|
return;
|
|
}
|
|
|
|
initialPages.map((op) => _fromResultPage(op)).forEach(_pages.add);
|
|
}
|
|
|
|
UnmodifiableListView<PagedResponse> get pages => UnmodifiableListView(_pages);
|
|
|
|
void clear() {
|
|
_pages.clear();
|
|
}
|
|
|
|
PagedResponse<bool> _fromResultPage(PagedResponse newPage) {
|
|
return PagedResponse(
|
|
true,
|
|
id: newPage.id,
|
|
previous: newPage.previous,
|
|
next: newPage.next,
|
|
);
|
|
}
|
|
|
|
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(_fromResultPage(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, _fromResultPage(newPage));
|
|
} else {
|
|
_pages.insert(currentIndex + 1, _fromResultPage(newPage));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|