Add infinite scroll and pull to refresh#499
Conversation
- refactor DRY widget - delete redundant provider - fix bad number formatting locale
…into beast/language-support
- use intl from sdk - import legacy provider
Setting already cleared in substarte service logout
- implement infinite scroll - implement pull to refresh
…into beast/language-support
…etwork/quantus-apps into beast/integrate-infinite-scroll-and-refresh-to-activity-screen
…etwork/quantus-apps into beast/integrate-infinite-scroll-and-refresh-to-activity-screen
…into beast/add-infinite-scroll-and-pull-to-refresh
| if (pagination == null || pagination.isFetching || !pagination.hasMore) return; | ||
|
|
||
| activeAccountPaginationNotifier(ref, _filterOption)?.fetchMore(); | ||
| } |
There was a problem hiding this comment.
Premature infinite scroll fetch
Medium Severity
_onScroll treats pixels >= maxScrollExtent - 200 as “near bottom,” but when the list is shorter than the viewport maxScrollExtent is often zero or small, so that condition is true at scroll offset zero and fetchMore() runs without the user reaching the end of the list.
Reviewed by Cursor Bugbot for commit a7a831a. Configure here.
|
I've done a thorough review of PR #499. Here's my analysis. PR #499 Review — Add infinite scroll and pull to refreshOverall this is a clean, well-scoped UX improvement. The core mechanics (shared Behavior issues1. Pull-to-refresh wipes the list to skeletons (UX regression). final targetAccountIds = _getAccountIds();
if (targetAccountIds.isEmpty) {
state = PaginationState.initial().copyWith(hasMore: false);
return;
}
// Reset to initial state to show loading
state = PaginationState.initial();
await _fetchPage(targetAccountIds);After that, the combined provider returns Pick one of:
2. void _onScroll() {
if (!_scrollController.hasClients) return;
final pos = _scrollController.position;
if (pos.pixels < pos.maxScrollExtent - _loadMoreThreshold) return;
final pagination = ref.read(activeAccountPaginationProvider(_filterOption));
if (pagination == null || pagination.isFetching || !pagination.hasMore) return;
activeAccountPaginationNotifier(ref, _filterOption)?.fetchMore();
}When the list is shorter than the viewport, if (pos.maxScrollExtent <= 0) return;
if (pos.pixels < pos.maxScrollExtent - _loadMoreThreshold) return;If you actually want auto-fill-to-viewport behavior (fetch more until the list fills the screen), do it explicitly in the controller after a fetch completes, not as a side-effect of touching the screen. 3. Bugbot's "filter change keeps scroll offset" — not actually a bug, but worth confirming. You added API / semantics4. hasMore: hasMore ?? this.hasMore,
isFetching: isFetching ?? this.isFetching,
error: error,
stackTrace: stackTrace,This is the right fix for "can't clear the error", but it changes semantics for every call site: any 5. if (pagination.isFetching && pagination.otherTransfers.isEmpty) {
return const AsyncValue.loading();
}You added Minor / style6. Logging inconsistency. Providers now use 7. Naming: 8. Duplicated 9. 10. Things I think are good
RecommendationApprove with the following changes requested:
The rest (naming, DRY of Want me to apply any of these as edits, or open follow-up comments on the PR? Per your rules, I won't post to GitHub or push without your go-ahead. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ebfbacb. Configure here.
| final pagination = ref.read(activeAccountPaginationProvider(_filterOption)); | ||
| if (pagination == null || pagination.isFetching) return; | ||
|
|
||
| await readActiveAccountPaginationNotifier(ref, _filterOption)?.loadingRefresh(); |
There was a problem hiding this comment.
Refresh races scroll pagination
Medium Severity
Pull-to-refresh scroll motion can invoke _onScroll while loadingRefresh has reset pagination to PaginationState.initial() with isFetching false, so fetchMore may start a second _fetchPage before refresh’s fetch sets isFetching, risking duplicate first-page rows or inconsistent offsets.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit ebfbacb. Configure here.


Summary
Continuation of this PR #493 , closing that one because of broken git history.
Note
Low Risk
UI and pagination-state changes reuse existing controllers; load-more errors are intentionally non-fatal for already-loaded lists.
Overview
Adds pull-to-refresh and infinite scroll on the v2 Activity screen for the active account’s filtered transaction history, wired to the existing filtered
UnifiedPaginationController.New Riverpod surface:
activeAccountPaginationProvider, helpers to read the pagination notifier, and shared filter params. Activity uses aScrollController(200px from bottom) to callfetchMore(),RefreshIndicator+loadingRefresh(), and a footer loader while the next page loads. Empty state stays scrollable so refresh still works.Pagination behavior is tightened for paging UX:
PaginationStategainshasLoadedChainDataandcopyWith(clearError: …); transaction providers only surfaceAsyncValue.errorwhen there is no loaded chain data yet—load-more failures keep showing cached rows (logged only). Fetches clear errors on retry viaclearError. Controller logging moves toquantusDebugPrint. Filter chip labels move toTransactionFilterLabelextension. Tests covercopyWitherror semantics; analyzer excludesbuild/**.Reviewed by Cursor Bugbot for commit ebfbacb. Bugbot is set up for automated code reviews on this repo. Configure here.