Skip to content

fix(map-view): preserve scroll position and other magic scrolling UX tricks#1216

Merged
simon-the-shark merged 11 commits into
mainfrom
1088-fixmultilayer-map-improve-scroll-behaviour
Jul 17, 2026
Merged

fix(map-view): preserve scroll position and other magic scrolling UX tricks#1216
simon-the-shark merged 11 commits into
mainfrom
1088-fixmultilayer-map-improve-scroll-behaviour

Conversation

@simon-the-shark

Copy link
Copy Markdown
Member

hopefully for the better :P

@simon-the-shark simon-the-shark self-assigned this Jul 17, 2026
@simon-the-shark simon-the-shark linked an issue Jul 17, 2026 that may be closed by this pull request
@simon-the-shark simon-the-shark changed the title fix(map-view): preserver scroll position and other magic scrolling UX tricks fix(map-view): preserve scroll position and other magic scrolling UX tricks Jul 17, 2026
@simon-the-shark
simon-the-shark force-pushed the 1088-fixmultilayer-map-improve-scroll-behaviour branch from fb1d305 to 6ee5521 Compare July 17, 2026 12:09
@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

elo żelo solvrowiczu 👋

This PR overhauls the map bottom-sheet scroll UX by capturing the sheet expansion and list scroll offset just before a marker is activated, then restoring them after deactivation via a post-frame retry loop (_SheetPositionRestorer). It also removes animated_list_plus in favour of a plain SliverList.builder to avoid scroll-extent collapse during list transitions, bumps Flutter to 3.44.6, and fixes a DST-sensitive date-range iteration in the calendar.

  • Scroll/sheet preservation: usePreservedSheetPosition now captures offset + size on marker activation and restores them (with animated restore for parkings, instant for multilayer) on deactivation; tab index is also preserved via pendingTabIndex on DraggableScrollableController.
  • ActiveMapItemSliver: active marker content is rendered as a SliverToBoxAdapter (not a SliverList) and NeverScrollableScrollPhysics is applied while a marker is active, preventing the prior list offset from being clamped mid-animation.
  • Calendar DST fix: _generateDateRange now uses DateTime(y, m, d + 1) instead of add(Duration(days: 1)), correctly crossing DST boundaries without skipping or doubling a day.

Confidence Score: 5/5

Safe to merge — the core restore logic is well-guarded with attachment/hasClients checks and a capped retry budget; no data loss or broken navigation paths identified.

All changes are additive UX improvements or clean-up. The scroll/sheet preserve-and-restore logic has appropriate isAttached/hasClients guards and bounded retry counts, errors are surfaced via FlutterError.reportError, and the calendar DST fix is straightforwardly correct. No changes to data persistence, auth, or network layers.

lib/features/bottom_scroll_sheet/hooks/use_preserved_scroll_offset.dart — the new _SheetPositionRestorer has no cancellation mechanism for concurrent restorers on rapid user taps, and the T == Parking type dispatch couples domain logic into generic restore code.

Important Files Changed

Filename Overview
lib/features/bottom_scroll_sheet/hooks/use_preserved_scroll_offset.dart New hook preserving sheet expansion and scroll offset across marker activation; uses post-frame retry loop (_SheetPositionRestorer) with proper error reporting but no cancellation path
lib/features/map_view/controllers/bottom_sheet_controller.dart Adds Expando-backed state (preservedPosition, lastSyncedTabIndex, pendingTabIndex) and safe animation helpers to the DraggableScrollableController extension; clean design
lib/features/bottom_scroll_sheet/use_tab_scroll_sync.dart Adds tab-index restore on remount via takePendingTabIndex/useMemoized, syncs lastSyncedTabIndex on every scroll update, and simplifies the ensureVisible overshoot workaround
lib/features/map_view/controllers/map_controller.dart Activation path now only calls resetSafe on activation, delegating sheet restoration to usePreservedSheetPosition on deactivation; background tap also skips resetSafe when an item was active
lib/features/bottom_scroll_sheet/map_data_sheet_list.dart Uses the new usePreservedSheetPosition hook, switches to ActiveMapItemSliver when a marker is active, sets NeverScrollableScrollPhysics while an item is active to prevent offset clamping
lib/features/calendar/bussiness/get_events_per_days_use_case.dart Fixes DST-sensitive date iteration: replaces add(Duration(days:1)) with DateTime constructor increment, correctly advancing the calendar day boundary across DST transitions
lib/features/bottom_scroll_sheet/active_map_item_sliver.dart New StatelessWidget rendering the selected marker tile as a SliverToBoxAdapter (avoids SliverList scroll-extent collapse bug)
lib/features/bottom_scroll_sheet/data_list.dart Removes SliverImplicitlyAnimatedList and animated_list_plus dependency in favour of plain SliverList.builder; simplifies _DataSliverList to StatelessWidget
lib/features/bottom_scroll_sheet/map_view_pop_behaviour.dart Back-button handler now skips resetSafe when a marker was active, matching the new restore flow; only resets when there is no active item to restore

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant MapController
    participant usePreservedSheetPosition
    participant BottomSheetController
    participant SheetPositionRestorer

    User->>MapController: tap marker (activate)
    MapController->>BottomSheetController: resetSafe()
    MapController->>usePreservedSheetPosition: "activeMarker prev=null → next=item"
    usePreservedSheetPosition->>BottomSheetController: "preservedPosition = {offset, sheetSize, tabIndex}"
    usePreservedSheetPosition->>ScrollController: jumpTo(0)

    User->>MapController: tap marker (deactivate)
    MapController->>usePreservedSheetPosition: "activeMarker prev=item → next=null"
    usePreservedSheetPosition->>BottomSheetController: clearPreservedPosition()
    usePreservedSheetPosition->>BottomSheetController: "pendingTabIndex = position.tabIndex"
    usePreservedSheetPosition->>SheetPositionRestorer: start() → schedulePostFrame

    SheetPositionRestorer->>BottomSheetController: animateToSafe / jumpToSafe (sheet size)
    SheetPositionRestorer->>ScrollController: jumpTo(savedOffset)

    Note over SheetPositionRestorer: Retries up to 12× if sheet/scroll not ready yet
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant MapController
    participant usePreservedSheetPosition
    participant BottomSheetController
    participant SheetPositionRestorer

    User->>MapController: tap marker (activate)
    MapController->>BottomSheetController: resetSafe()
    MapController->>usePreservedSheetPosition: "activeMarker prev=null → next=item"
    usePreservedSheetPosition->>BottomSheetController: "preservedPosition = {offset, sheetSize, tabIndex}"
    usePreservedSheetPosition->>ScrollController: jumpTo(0)

    User->>MapController: tap marker (deactivate)
    MapController->>usePreservedSheetPosition: "activeMarker prev=item → next=null"
    usePreservedSheetPosition->>BottomSheetController: clearPreservedPosition()
    usePreservedSheetPosition->>BottomSheetController: "pendingTabIndex = position.tabIndex"
    usePreservedSheetPosition->>SheetPositionRestorer: start() → schedulePostFrame

    SheetPositionRestorer->>BottomSheetController: animateToSafe / jumpToSafe (sheet size)
    SheetPositionRestorer->>ScrollController: jumpTo(savedOffset)

    Note over SheetPositionRestorer: Retries up to 12× if sheet/scroll not ready yet
Loading

Reviews (3): Last reviewed commit: "refactor: streamline error reporting in ..." | Re-trigger Greptile

Comment thread lib/features/bottom_scroll_sheet/active_map_item_sliver.dart Outdated
Comment thread lib/features/bottom_scroll_sheet/hooks/use_preserved_scroll_offset.dart Outdated
…mSliver and enhance scroll restoration logic in use_preserved_scroll_offset
…y consolidating FlutterErrorDetails construction
@simon-the-shark
simon-the-shark merged commit 2b58e18 into main Jul 17, 2026
10 checks passed
@simon-the-shark
simon-the-shark deleted the 1088-fixmultilayer-map-improve-scroll-behaviour branch July 17, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(multilayer-map): improve scroll behaviour

1 participant