fix: persist search page scroll offset between rebuilds (#22733)

fix: persist search scroll between rebuilds

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
shenlong
2025-10-08 20:30:51 +05:30
committed by GitHub
parent 6f3cb4f1bb
commit b3342323de
5 changed files with 37 additions and 16 deletions
@@ -599,9 +599,9 @@ class _SearchResultGrid extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final searchResult = ref.watch(paginatedSearchProvider);
final assets = ref.watch(paginatedSearchProvider.select((s) => s.assets));
if (searchResult.totalAssets == 0) {
if (assets.isEmpty) {
return const _SearchEmptyContent();
}
@@ -615,6 +615,7 @@ class _SearchResultGrid extends ConsumerWidget {
if (metrics.pixels >= metrics.maxScrollExtent && isVerticalScroll && !isBottomSheetNotification) {
onScrollEnd();
ref.read(paginatedSearchProvider.notifier).setScrollOffset(metrics.maxScrollExtent);
}
return true;
@@ -623,17 +624,18 @@ class _SearchResultGrid extends ConsumerWidget {
child: ProviderScope(
overrides: [
timelineServiceProvider.overrideWith((ref) {
final timelineService = ref.watch(timelineFactoryProvider).fromAssets(searchResult.assets);
final timelineService = ref.watch(timelineFactoryProvider).fromAssets(assets);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
key: ValueKey(searchResult.totalAssets),
key: ValueKey(assets.length),
groupBy: GroupAssetsBy.none,
appBar: null,
bottomSheet: const GeneralBottomSheet(minChildSize: 0.20),
snapToMonth: false,
initialScrollOffset: ref.read(paginatedSearchProvider.select((s) => s.scrollOffset)),
),
),
),
@@ -24,12 +24,20 @@ class PaginatedSearchNotifier extends StateNotifier<SearchResult> {
return false;
}
state = SearchResult(assets: [...state.assets, ...result.assets], nextPage: result.nextPage);
state = SearchResult(
assets: [...state.assets, ...result.assets],
nextPage: result.nextPage,
scrollOffset: state.scrollOffset,
);
return true;
}
void setScrollOffset(double offset) {
state = state.copyWith(scrollOffset: offset);
}
clear() {
state = const SearchResult(assets: [], nextPage: 1);
state = const SearchResult(assets: [], nextPage: 1, scrollOffset: 0.0);
}
}
@@ -40,6 +40,7 @@ class Timeline extends StatelessWidget {
this.groupBy,
this.withScrubber = true,
this.snapToMonth = true,
this.initialScrollOffset,
});
final Widget? topSliverWidget;
@@ -51,6 +52,7 @@ class Timeline extends StatelessWidget {
final GroupAssetsBy? groupBy;
final bool withScrubber;
final bool snapToMonth;
final double? initialScrollOffset;
@override
Widget build(BuildContext context) {
@@ -78,6 +80,7 @@ class Timeline extends StatelessWidget {
bottomSheet: bottomSheet,
withScrubber: withScrubber,
snapToMonth: snapToMonth,
initialScrollOffset: initialScrollOffset,
),
),
),
@@ -93,6 +96,7 @@ class _SliverTimeline extends ConsumerStatefulWidget {
this.bottomSheet,
this.withScrubber = true,
this.snapToMonth = true,
this.initialScrollOffset,
});
final Widget? topSliverWidget;
@@ -101,6 +105,7 @@ class _SliverTimeline extends ConsumerStatefulWidget {
final Widget? bottomSheet;
final bool withScrubber;
final bool snapToMonth;
final double? initialScrollOffset;
@override
ConsumerState createState() => _SliverTimelineState();
@@ -124,7 +129,10 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
@override
void initState() {
super.initState();
_scrollController = ScrollController(onAttach: _restoreScalePosition);
_scrollController = ScrollController(
initialScrollOffset: widget.initialScrollOffset ?? 0.0,
onAttach: _restoreScalePosition,
);
_eventSubscription = EventStream.shared.listen(_onEvent);
final currentTilesPerRow = ref.read(settingsProvider).get(Setting.tilesPerRow);