Skip to content

Improve haptic fidelity: consolidate backend, add global config, and fix existing gaps#145

Draft
ElectricCookie wants to merge 139 commits into
mainfrom
feature/issue-139-haptic-fidelity
Draft

Improve haptic fidelity: consolidate backend, add global config, and fix existing gaps#145
ElectricCookie wants to merge 139 commits into
mainfrom
feature/issue-139-haptic-fidelity

Conversation

@ElectricCookie

Copy link
Copy Markdown
Collaborator

Resolves #139

ElectricCookie and others added 30 commits March 27, 2025 22:38
…ize it

- Removed the highlighter logic from CodeBlock and replaced it with the new SourceCode component for better separation of concerns.
- Simplified the CodeBlock state management by eliminating unnecessary variables and methods related to highlighter themes.
- Updated the clipboard functionality to directly use the widget's code.
- Refactored multiple components to import the new component_well structure for consistency across the codebase.
- Previously, when we passed an assumedItemHeight to LdList and scrolled to a certain position, it would load all items until that position
- Now, when we pass an assumedItemHeight to LdList and scroll to a certain position, it will skip the items in-between using a debounce strategy
- We also support "lazy loading" of pages in both directions (top and bottom)
…y and remove glitchy `PositionRetainedScrollPhysics`
Using the scroll extent of the scroll controller and the page size produced glitchy effects. It seems to be more reliable to just use the item height of the first item that is actually being rendered.
- Added 'circular' boolean property to toggle between circular and rectangular avatars.
- Introduced 'size' property to customize avatar dimensions.
- Updated height and width calculations to utilize the new size property.
- Adjusted background color and border radius based on the circular property.
- Updated the alpha value in the LdTag widget to be consistently set to 50 for both light and dark themes, ensuring uniformity in appearance.
- Wrapped leading icon in an IconTheme to ensure consistent theming.
- Adjusted text styles for title and subtitle to improve readability and alignment with theme.
- Enhanced spacing and layout for better visual structure.
…Modal

- Increased the small action bar height from 64 to 70 for better UI consistency.
- Enhanced device type detection by ensuring context is mounted and media query is valid before accessing device size.
- Adjusted the font size for LdSize.l from 16 to 14.
- Increased the font size for LdSize.l from 28 to 32 for improved readability.
- Removed redundant font weight assignment for LdSize.l in LdTextType.label, streamlining the text style logic.
- Updated loading and error text display to use LdTextP for consistent styling.
- Improved dialog layout with additional padding and a constrained box for better visual structure.
- Adjusted background color and border properties for improved theming consistency.
- Introduced safe context handling to ensure correct navigator usage based on the useRootNavigator property.
- Added a dispose method for potential future resource management.
- Removed commented-out code for the PortalTarget widget to improve code clarity.
- Reformatted the BoxDecoration for better readability and consistency.
- Replaced the theme-dependent icon with a consistent LdAvatar for better visual integration.
- Changed LdTextPl to LdTextP for uniform text styling in the no items found message.
- Removed unnecessary theme variable to streamline the build method.
ElectricCookie and others added 30 commits April 15, 2026 14:27
Removes ComponentWell wrapper from form demo, updates LdSelect usage
with a label, removes maxVisibleTabs control from tab demo (deprecated),
and reformats LdAppBar.callbacks initializer in main.dart for clarity.
Also adds a debug print for the window-ready event.
Adds super_native_extensions and irondash_engine_context pod dependencies,
removes path_provider_foundation, updates AppDelegate to use
FlutterImplicitEngineDelegate, updates Info.plist for UISceneManifest,
removes MinimumOSVersion from AppFrameworkInfo.plist, and bumps CocoaPods
to 1.16.2.
…) (#98)

* fix: various smaller consistatency and bugs in monkey

* refactor to new monkey patterns

* refactor: use named routes, cleanup touchable

* refactor(monkey): rework monkey routes to tree-based buildMonkeyRouteTree API

- Use buildMonkeyRouteTree/MonkeyRouteNode for nested project/file routes
- Update repositoryBuilder signatures to accept (context, state)
- Remove manual Provider/ShellRoute nesting in AppRouter
- Add MonkeyRouteScope and MonkeyRouteTree helpers
- Update monkey tests and example app patterns

* feat(appbar): add LdAppBarMetrics value object and appbar_state.dart (Stage 1)

- Create LdAppBarMetrics immutable value object with position, barHeight,
  edgeMargin, hideOffset, isScrolledUnder, level fields
- Add consumedInsets computed getter for 4-directional EdgeInsets
- Re-export LdAppBarPosition from appbar_state.dart via index.dart
- Add unit tests for value equality, consumedInsets, and copyWith

Part of issue #91 — Stage 1 (#92)

* feat(appbar): rework AppBarFrame into Stack layout engine (Stage 2)

- Add wrappedChild and scrollBehavior params to AppBarFrame
- Stack-mode: wraps child in Stack with Positioned bar surface,
  Transform.translate for scroll-hide, NotificationListener for
  scroll tracking
- Provides LdAppBarMetrics via Provider.value to wrapped subtree
- Patches MediaQuery.padding additively with consumedInsets
- Resolves level from nearest ancestor LdAppBarMetrics context
- Legacy-mode preserved for backward compat until Stage 3
- Add 9 widget tests in appbar_frame_test.dart

Part of issue #91 — Stage 2 (#93)

* feat(appbar): rework LdAppBar and LdTabNavigation to wrapper API (Stage 3)

- Add child: Widget? parameter to LdAppBar, LdTabNavigation (stack-mode)
- Deprecate order parameter (kept as no-op for backward compat)
- Remove LdAppBarRegistryEntry and LdAppBarScrollWrapper from stack-mode path
- Delegate to AppBarFrame(wrappedChild: child) when child is provided
- Add insideDecorationBuilder/outsideDecorationBuilder to AppBarFrame
  for reactive scroll-under decoration
- closeModalButton uses LdAppBarMetrics from context in stack-mode
- Legacy-mode (no child) preserved for backward compat until Stage 4
- Update appbar_test.dart and tab_navigation_test.dart to new API
- 22/22 appbar tests, 14/14 tab_navigation tests pass

Part of issue #91 — Stage 3 (#94)

* feat(scaffold): remove AppBarRegistry from LdScaffold, deprecate appBars (Stage 4)

- Remove AppBarRegistry widget and bodyPadding ValueListenableBuilder from build()
- Remove Stack with appBars.reversed children; body now rendered directly
- Remove appbar_registry.dart import from scaffold.dart
- Deprecate appBars param (kept as no-op for ~60 call sites awaiting Stage 6)
- Body bars now use wrapper pattern: LdAppBar(child: body)
- Update scaffold_test.dart: migrate 3 tests to wrapper API, add 3 new tests
- 17/17 scaffold tests pass

Part of issue #91 — Stage 4 (#95)

* feat(appbar): remove registry dead code, rework ScrolledUnderBuilder and drawer buttons (Stage 5)

- Delete appbar_registry.dart, appbar_scroll_wrapper.dart, scaffold_layout_state.dart
- ScrolledUnderBuilder simplified to StatelessWidget reading LdAppBarMetrics? from context
- OpenDrawerButton and CloseDrawerButton use LdAppBarMetrics for level/position check
- Remove LdDrawerLayout widget-type ancestor check (LdDrawerSlot provider is sufficient)
- Remove remaining legacy-mode registry/scroll_wrapper code from appbar.dart and tab_navigation.dart
- Export appbar_scroll_behavior.dart from index.dart
- 27/27 appbar tests pass, 0 analysis errors

Part of issue #91 — Stage 5 (#96)

* feat(appbar): migrate all call sites to wrapper API and regenerate goldens (Stage 6)

- Migrate LdMonkeyAppBar to accept child parameter, forward to LdAppBar
- Migrate all internal library files to wrapper pattern:
  - exception_dialog.dart, time_picker.dart, date_picker.dart
  - choose/choose.dart, modal/utils.dart (both usages)
  - devtools extension main.dart
- Migrate all example app files (agent partial work from prior run)
- Rewrite appbar_golden_test.dart, scaffold_golden_test.dart,
  tab_navigation_golden_test.dart, modal_golden_test.dart to new API
- Migrate modal_test.dart to new wrapper pattern
- Regenerate all golden images with new Stack-based layout
- Zero analysis errors; pre-existing test failures (list_test, repository_test,
  time_picker_test) are unrelated to this change

Completes issue #91 — Stage 6 (#97)

* fix(appbar): fix padding accumulation in consumedInsets and repair example formatting

- consumedInsets now subtracts edgeMargin from the visible height instead of
  adding it, so nested bars no longer double-count ancestor insets
- Move MeasureSize outside AnimatedContainer so bar height is measured after
  layout, preventing spurious padding in stacked bars
- Update appbar_state_test.dart expectations to match corrected formula
- Add regression test: nested same-position bars should not add an extra gap
- Fix LdOrb dispose order (super.dispose() before controller.dispose())
- Reformat example files (chemical_screen, component_well, demo_code_dialog,
  drawer) to correct indentation after LdScaffoldBody child extraction
- Remove unused flutter/services and liquid/main.dart imports from drawer.dart
* fix: various smaller consistatency and bugs in monkey

* refactor to new monkey patterns

* refactor: use named routes, cleanup touchable

* refactor(monkey): rework monkey routes to tree-based buildMonkeyRouteTree API

- Use buildMonkeyRouteTree/MonkeyRouteNode for nested project/file routes
- Update repositoryBuilder signatures to accept (context, state)
- Remove manual Provider/ShellRoute nesting in AppRouter
- Add MonkeyRouteScope and MonkeyRouteTree helpers
- Update monkey tests and example app patterns

* feat(appbar): add LdAppBarMetrics value object and appbar_state.dart (Stage 1)

- Create LdAppBarMetrics immutable value object with position, barHeight,
  edgeMargin, hideOffset, isScrolledUnder, level fields
- Add consumedInsets computed getter for 4-directional EdgeInsets
- Re-export LdAppBarPosition from appbar_state.dart via index.dart
- Add unit tests for value equality, consumedInsets, and copyWith

Part of issue #91 — Stage 1 (#92)

* feat(appbar): rework AppBarFrame into Stack layout engine (Stage 2)

- Add wrappedChild and scrollBehavior params to AppBarFrame
- Stack-mode: wraps child in Stack with Positioned bar surface,
  Transform.translate for scroll-hide, NotificationListener for
  scroll tracking
- Provides LdAppBarMetrics via Provider.value to wrapped subtree
- Patches MediaQuery.padding additively with consumedInsets
- Resolves level from nearest ancestor LdAppBarMetrics context
- Legacy-mode preserved for backward compat until Stage 3
- Add 9 widget tests in appbar_frame_test.dart

Part of issue #91 — Stage 2 (#93)

* feat(appbar): rework LdAppBar and LdTabNavigation to wrapper API (Stage 3)

- Add child: Widget? parameter to LdAppBar, LdTabNavigation (stack-mode)
- Deprecate order parameter (kept as no-op for backward compat)
- Remove LdAppBarRegistryEntry and LdAppBarScrollWrapper from stack-mode path
- Delegate to AppBarFrame(wrappedChild: child) when child is provided
- Add insideDecorationBuilder/outsideDecorationBuilder to AppBarFrame
  for reactive scroll-under decoration
- closeModalButton uses LdAppBarMetrics from context in stack-mode
- Legacy-mode (no child) preserved for backward compat until Stage 4
- Update appbar_test.dart and tab_navigation_test.dart to new API
- 22/22 appbar tests, 14/14 tab_navigation tests pass

Part of issue #91 — Stage 3 (#94)

* feat(scaffold): remove AppBarRegistry from LdScaffold, deprecate appBars (Stage 4)

- Remove AppBarRegistry widget and bodyPadding ValueListenableBuilder from build()
- Remove Stack with appBars.reversed children; body now rendered directly
- Remove appbar_registry.dart import from scaffold.dart
- Deprecate appBars param (kept as no-op for ~60 call sites awaiting Stage 6)
- Body bars now use wrapper pattern: LdAppBar(child: body)
- Update scaffold_test.dart: migrate 3 tests to wrapper API, add 3 new tests
- 17/17 scaffold tests pass

Part of issue #91 — Stage 4 (#95)

* feat(appbar): remove registry dead code, rework ScrolledUnderBuilder and drawer buttons (Stage 5)

- Delete appbar_registry.dart, appbar_scroll_wrapper.dart, scaffold_layout_state.dart
- ScrolledUnderBuilder simplified to StatelessWidget reading LdAppBarMetrics? from context
- OpenDrawerButton and CloseDrawerButton use LdAppBarMetrics for level/position check
- Remove LdDrawerLayout widget-type ancestor check (LdDrawerSlot provider is sufficient)
- Remove remaining legacy-mode registry/scroll_wrapper code from appbar.dart and tab_navigation.dart
- Export appbar_scroll_behavior.dart from index.dart
- 27/27 appbar tests pass, 0 analysis errors

Part of issue #91 — Stage 5 (#96)

* feat(appbar): migrate all call sites to wrapper API and regenerate goldens (Stage 6)

- Migrate LdMonkeyAppBar to accept child parameter, forward to LdAppBar
- Migrate all internal library files to wrapper pattern:
  - exception_dialog.dart, time_picker.dart, date_picker.dart
  - choose/choose.dart, modal/utils.dart (both usages)
  - devtools extension main.dart
- Migrate all example app files (agent partial work from prior run)
- Rewrite appbar_golden_test.dart, scaffold_golden_test.dart,
  tab_navigation_golden_test.dart, modal_golden_test.dart to new API
- Migrate modal_test.dart to new wrapper pattern
- Regenerate all golden images with new Stack-based layout
- Zero analysis errors; pre-existing test failures (list_test, repository_test,
  time_picker_test) are unrelated to this change

Completes issue #91 — Stage 6 (#97)

* fix(appbar): fix padding accumulation in consumedInsets and repair example formatting

- consumedInsets now subtracts edgeMargin from the visible height instead of
  adding it, so nested bars no longer double-count ancestor insets
- Move MeasureSize outside AnimatedContainer so bar height is measured after
  layout, preventing spurious padding in stacked bars
- Update appbar_state_test.dart expectations to match corrected formula
- Add regression test: nested same-position bars should not add an extra gap
- Fix LdOrb dispose order (super.dispose() before controller.dispose())
- Reformat example files (chemical_screen, component_well, demo_code_dialog,
  drawer) to correct indentation after LdScaffoldBody child extraction
- Remove unused flutter/services and liquid/main.dart imports from drawer.dart

* fix(spring): skip ticker when ldDisableAnimations; use addPostFrameCallback

- Guard ticker creation/start with !ldDisableAnimations in both LdSpring
  and LdChainedSprings so no unnecessary ticks fire during tests.
- Replace Future.delayed(Duration.zero) with
  WidgetsBinding.instance.addPostFrameCallback for the onAnimationEnd
  callback when animations are disabled, avoiding dangling timers that
  cause post-test failures.

* fix(appbar): use addPostFrameCallback; read level; drop AnimatedContainer

- Replace Future.delayed(Duration.zero) with addPostFrameCallback in
  _handleFocusChange to avoid dangling timers in widget tests.
- Switch AppBarFrame._calculateLevel from context.watch to context.read:
  level is a structural property (nesting depth) that doesn't change
  reactively; watching caused unbounded rebuild cascades whenever any
  parent-bar metric changed.
- Replace AnimatedContainer with plain Container in AppBarFrame: the
  animated transitions were redundant and interacted poorly with the
  render pipeline.

* fix(overflow): single-pass layout for flexible children

Pre-compute final widths for Expanded/flexible children before the
per-child layout loop so each child is laid out exactly once with its
final dimensions. The previous approach laid out all children first,
then re-laid out flexible children with expanded sizes, causing widgets
like AnimatedSize to restart their animations every frame and never
settle.

* fix(list): auto-fetch on mount; fix initialItems not setting totalItems

- LdListWidget.didChangeDependencies now schedules a post-frame
  refreshList when the paginator has no items and isn't already busy,
  so lists backed by a fresh paginator load without requiring an
  external trigger.
- LdPaginator: set totalItems = initialItems.length when initialItems
  are provided; previously totalItems stayed 0 even when items were
  pre-populated, causing the list to believe it was empty.

* fix(monkey): several correctness fixes

- PreventAutoFocus: only schedule addPostFrameCallback when _excluding
  is true to prevent an infinite rebuild loop (previously the callback
  was registered on every build).
- LdChoosePage: use context.watch<LdMonkeySortAndFilterState?> (nullable)
  so the widget works when mounted outside a Monkey shell.
- LdSortOption: add hashCode override (name, isOn, direction) to match
  the existing operator== and satisfy Dart equality contracts.
- LdRepository: forward super.initialItems parameter so callers can
  pre-populate the repository without a network round-trip.

* fix(card/choose/liquid_orb): minor correctness fixes

- LdCard: use CrossAxisAlignment.stretch so child widgets fill the full
  card width instead of being left-aligned.
- LdChoosePage: already committed as part of monkey fix (choose.dart
  null-safe watch).
- LdOrb: dispose _animationController before calling super.dispose to
  avoid using the ticker provider after it has been deactivated.

* fix(tab_navigation/list_item_animation): respect ldDisableAnimations

- LdTabNavigation: use ScrollController.jumpTo instead of animateTo when
  ldDisableAnimations is true, so tests don't hang waiting for animations
  to complete.
- LdListItemAnimation: return LdReveal.quick widgets (instant reveal/hide)
  for deleting/rolledBackDeletion states when animations are disabled,
  avoiding flutter_animate calls that require a running ticker.

* test(test_utils): refactor multi_golden; add writeFailureScreenshot; widgetTreeOptionsOverrides

multi_golden_test.dart:
- Capture the golden widget tree AFTER the full scenario builder has run
  (including post-placement interactions like opening a modal), fixing
  snapshots that only captured the pre-interaction state.
- Add writeFailureScreenshot helper using WidgetTester.runAsync +
  OffsetLayer.toImage to avoid blocking the test process (replaces the
  previous RenderRepaintBoundary.toImage call inside the test zone).
- Add widgetTreeOptionsOverrides parameter for per-scenario
  WidgetTreeOptions (strippedWidgets, findWidget, etc.).
- Add pumpAndSettle after placeWidget so GoRouter finishes its initial
  route before scenario interactions begin.
- Minor formatting / style cleanup.

ld_frame.dart:
- Remove UniqueKey() on the outer KeyedSubtree; the key forced a full
  widget-tree replacement on every frame creation, discarding state
  unnecessarily.
- Minor formatting cleanup.

* test: update tests for new APIs and animation-off guards

- list_test.dart: capture BuildContext via Builder and pass it to
  refreshList(context:); update fetchListFunction signature to use
  FetchPageParameters.
- radio_test.dart: set ldDisableAnimations=true; fix expected color from
  idle to active (matches actual LdRadio rendering with color param).
- repository_test.dart: migrate to FetchPageParameters / FetchOffsetParameters
  signatures; add _pumpAndGetContext / _loadRepository helpers; simplify
  createRepository helper by removing now-redundant params.
- monkey/*_test.dart + test_utils.dart: adapt to updated monkey APIs and
  filter/sort option signatures (no functional logic changes, only
  signature alignment).
- accordion_golden_test.dart, avatar_golden_test.dart,
  date_picker_golden_test.dart: minor test setup adjustments.

* fix: time picker appearance and funcitonality

* chore: fix linting

* chore: fix linting

* chore: update sample goldens

* chore: update sample goldens

* chore: update Flutter version in PR validation workflow to 3.41.7
* feat(multi_panel): Stage 1 - add LdPanelPosition, LdPanelRole enums and extend LdMultiPanelChildState

* chore(api_guard): regenerate after Stage 1 enum additions

* feat(multi_panel): Stage 2 - rewrite LdMultiPanelLayout with 2-panel API, update LdDrawerLayout and MonkeyShell

* test(golden): regenerate scaffold golden trees after LdDrawerLayout rewrite (Stage 3)

* test(multi_panel): Stage 4 - add widget test suite for LdMultiPanelLayout and LdDrawerLayout

* fix(multi_panel): bypass spring during resize drag for instant panel tracking

When _isResizing is true, render body and panel with direct Positioned
values instead of wrapping them in LdSpring. This eliminates the
spring lag and overshoot that caused sluggish feel and panel overlap
during drag. Spring animations are preserved for show/hide transitions.

* fix(multi_panel): fix scrim tap dismiss and initial panelVisible seeding

Bug 1 – tapping the body area did not close the panel in stacked mode:
The ModalBarrier(dismissible: false) inside the GestureDetector absorbed
all pointer events before onTap could fire. Replaced with a single
ModalBarrier(dismissible: true, onDismiss: ...) so the barrier itself
handles the tap correctly.

Bug 2 – initial open state ignored on desktop (LdDrawerLayout):
LdMultiPanelLayout.initState seeded _panelVisible from initialPanelVisible
only, ignoring the controlled panelVisible prop. LdDrawerLayout sets
_panelVisible = true in its own initState (desktop auto-open) but never
passes initialPanelVisible, so the widget always started hidden. Fix: seed
from widget.panelVisible ?? widget.initialPanelVisible ?? false.

Regression tests added for both bugs (tests 13 and 14).

* feat(example): Stage 5 - rewrite multi_panel_layout demo with new 2-panel API

- Demo shows mode, panelPosition, allowResize, panelVisible controls
- Panel and body display live LdMultiPanelChildState values (role, left, width, isDragging)
- api_guard/api.json regenerated: PanelWidth removed, LdPanelPosition/LdPanelRole present
- Fix drawer_layout mounted guard on _handleHistoryEntryRemoved
- MonkeyShell: enable allowResize on detail panel by default

* chore(example): clean up router, scaffold, and drawer navigation

* fix(multi_panel): fix spring drag lag, mode-switch flicker, and resize flicker (#107)

- Stage 1: extract _buildPanelSpring with Key('panel') shared across modes; unify body spring keys to prevent teardown on sideBySide↔stacked switch
- Stage 2: decouple spring target from drag offset in stacked mode; apply effectiveOffset additively in builder so spring physics only engage on gesture end; LdMultiPanelChildState.dragOffset now reports clamped effectiveOffset
- Stage 3: remove _isResizing conditional in _buildSideBySide; LdSpring nodes stay in tree during resize; resize delta applied additively in builder to prevent widget.body/panel remounting

Closes #108, #109, #110

* fix(multi_panel): use LdSpring overriden=true during drag/resize for 1:1 tracking

Replace the additive-offset-in-builder approach with the simpler overriden pattern:
- During stacked swipe: overriden=true, spring.position = snapped + effectiveOffset,
  so the spring tracks the finger immediately with no physics catch-up. When the
  finger lifts, overriden=false and the spring animates from the mid-drag position
  to the snapped target naturally.
- During sideBySide resize: same pattern on body_left/body_right and panel springs;
  spring.position = stable + resizeDelta with overriden=_isResizing.
- Remove additive delta from all builder lambdas (state.position is the full value).
- Remove debug print statement.
- Update test 15 to verify mid-drag 1:1 tracking via raw gesture steps.

* chore: add overriden parameter to LdSpring
…yout and MonkeyShell

- Update _drawerBorder getter to return null when not side-by-side.
- Simplify LdDrawerLayout by removing unnecessary container decoration.
- Modify multi-panel layout to ensure correct border application based on panel position.
- source_code.dart: use `final` + add `listen: true` to LdTheme.of so
  syntax highlighting theme reacts to dark-mode toggles
- autospace.dart: add smaller (LdSize.s) spacing between headline and
  label text pairs, preventing the oversized LdSize.l gap
- checkbox.dart: pass `widget.size` (not clamped `size`) to LdFormLabel
  so the label respects the caller-specified size
- typography.dart: reduce small-theme headline sizes (xs→12, s→14,
  m→16, l→18) for tighter small-screen typography
* fix: make  allow tap outside default to false

* fix: secondary bar respects system UI insets during parent hide

- MeasureSize moved to inner container so _innerHeight is stable;
  barHeight = stableEdgeMargin + _innerHeight never changes during hide.
- Introduce animatedEdgeMargin for bar surface outer padding: tracks the
  parent bar's live visible height (floored at device safe-area) so the
  secondary bar's content always sits at or above the safe-area edge.
- translateY now uses own hideOffset only; parent-tracking is handled
  entirely by animatedEdgeMargin, avoiding the double-count that pushed
  nested bar content off the safe-area boundary.
- Update nested-bar tracking test to assert the new correct behaviour:
  inner bar slides up with outer bar and stops at the device safe-area
  floor when the outer bar is fully hidden.

* fix: clamp spring position and hide bar 1px past barHeight

- maxOffset and snap target are now barHeight+1 so the bar travels
  1 extra pixel off-screen when fully hidden, ensuring any bottom
  border/shadow is fully clipped and not visible.
- Clamp animatedHideOffset to 0..barHeight+1 so the spring can neither
  pull the bar below its resting position (detaching from the edge)
  nor overshoot the fully-hidden position.

* fix: restore floating bar gap above surface

The edge padding for floating bars must ADD extraPadding on the edge
axis rather than just clamp via atLeast. Using atLeast caused the gap
to be swallowed by the (larger) animatedEdgeMargin from the parent bar,
making stacked floating bars appear flush against each other.

* fix: floating bar gap missing between nested bars

MeasureSize is on the inner container, so _innerHeight does not include
the floating edge gap (extraPadding.top). stablePadding and barHeight
both excluded the gap, so nested bars read a stableEdgeMargin that put
their outer container flush against the inner content of the parent bar.

Fix: introduce _floatingEdgeGap() and add it to barHeightWithGap and
stablePaddingWithGap inside LayoutBuilder so nested bars correctly
account for the full rendered height of the floating parent.

* fix: appbar scroll implementation not snapping correctly
This fixes issues occuring after updating to Flutter 3.44.0.
pass the missing router controller provider so filter buttons work again, and rebuild modal state from router changes so selected filters/sorts show up on the first click.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve haptic fidelity: consolidate backend, add global config, and fix existing gaps

2 participants