Last active
December 30, 2021 04:46
-
-
Save rutvik110/888ca4058e6cb28dad19af761e2f2ece to your computer and use it in GitHub Desktop.
Pagination With StateNotifier
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:coves_management/notifiers/pagination/pagination_notifier_state.dart'; | |
import 'package:flutter_riverpod/flutter_riverpod.dart'; | |
import 'package:logging/logging.dart'; | |
class PaginationNotifier<T> extends StateNotifier<PaginationNotifierState<T>> { | |
PaginationNotifier({required this.fetchNextItems, required this.hitsPerPage}) | |
: super(const PaginationNotifierState.data([], false)) { | |
init(); | |
} | |
final Logger logger = Logger('PaginationNotifier'); | |
final Future<List<T>> Function(T? item, int offset, | |
{String? query, required bool forceNetwork}) fetchNextItems; | |
final int hitsPerPage; | |
String _currentQuery = ""; | |
final List<T> _items = []; | |
void init() { | |
if (_items.isEmpty) { | |
fetchNextPage(); | |
} | |
} | |
bool get _canLoadNextPage => state.maybeWhen( | |
dataLoading: (_) => false, | |
data: (_, hasReachedMax) => !hasReachedMax, | |
orElse: () => true, | |
); | |
Future<void> loadQuery(String query) { | |
_currentQuery = query; | |
return fetchNextPage(skipLoadNextPageCheck: true, clearCurrentList: true); | |
} | |
Future<void> fetchNextPage( | |
{bool skipLoadNextPageCheck = false, | |
bool clearCurrentList = false, | |
bool forceNetwork = false}) async { | |
if (!mounted) { | |
logger.warning("fetchNextPage called on unmounted PaginationNotifier"); | |
return; | |
} | |
if (!_canLoadNextPage && !skipLoadNextPageCheck) { | |
return; | |
} | |
try { | |
state = PaginationNotifierState.dataLoading(_items); | |
final List<T> result = _items.isEmpty || clearCurrentList | |
? await fetchNextItems(null, 0, | |
query: _currentQuery, forceNetwork: forceNetwork) | |
: await fetchNextItems(_items.last, _items.length, | |
query: _currentQuery, forceNetwork: forceNetwork); | |
if (clearCurrentList) { | |
_items.clear(); | |
} | |
if (result.isEmpty) { | |
state = PaginationNotifierState.data(_items, true); | |
} else if (result.length < hitsPerPage) { | |
state = PaginationNotifierState.data(_items..addAll(result), true); | |
} else { | |
state = PaginationNotifierState.data(_items..addAll(result), false); | |
} | |
} catch (e, stk) { | |
print(mounted); | |
state = PaginationNotifierState.error(e, stk); | |
} | |
} | |
} | |
/// Pagination State | |
import 'package:flutter/foundation.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:freezed_annotation/freezed_annotation.dart'; | |
part 'pagination_notifier_state.freezed.dart'; | |
@freezed | |
abstract class PaginationNotifierState<T> with _$PaginationNotifierState<T> { | |
const factory PaginationNotifierState.data( | |
List<T> items, bool hasReachedMax) = _Data; | |
const factory PaginationNotifierState.dataLoading(List<T> movies) = | |
_DataLoading; | |
const factory PaginationNotifierState.error(Object? e, [StackTrace? stk]) = | |
_Error; | |
} | |
/// Controller listening to scrolling updates and fetching items if user reaches end of list | |
@override | |
void initState() { | |
super.initState(); | |
_invoiceScrollController = ScrollController(); | |
_invoiceScrollController.addListener(() { | |
double maxScroll = _invoiceScrollController.position.maxScrollExtent; | |
double currentScroll = _invoiceScrollController.position.pixels; | |
double delta = MediaQuery.of(context).size.width * 0.20; | |
if (maxScroll - currentScroll <= delta) { | |
widget.onEnd(lastItem); | |
} | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment