relatica/lib/friendica_client/pages_manager.dart

118 wiersze
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;
}
}