Merge FB-03: grid-snapped HUD widgets with auto-fit text
# Conflicts: # docs/feedback/FB-03-grid-snapped-hud-widgets.md # lib/src/ui/record/record_screen.dart
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# FB-03 — Grid-snapped HUD widgets with auto-fit, centered text
|
||||
|
||||
**Depends on** — · **Size** L · **Status** Not started
|
||||
**Depends on** — · **Size** L · **Status** Done
|
||||
|
||||
## Goal
|
||||
Rework the customizable HUD telemetry widgets (built in UI-04) from free-form fractional
|
||||
@@ -601,3 +601,61 @@ FB-02 (hiding the idle Speed panel — separate ticket, this one only touches th
|
||||
recording-state HUD widgets themselves). Making widget text grow to actually fill a
|
||||
larger grid span (see Risks). Any change to which metrics exist or their default
|
||||
visibility set — `HudMetric`'s own enum and `label`s are untouched.
|
||||
|
||||
## Outcome
|
||||
Implemented exactly per the Design section above, no deviations from the approach:
|
||||
|
||||
- `lib/src/hud/hud_widget_layout.dart` rewritten with the 4x8 int grid
|
||||
(`hudGridColumns`/`hudGridRows`), `col`/`row`/`colSpan`/`rowSpan` fields,
|
||||
`clampedToGrid()`, top-level `hudRectsOverlap()`, updated `toJson`/`fromJson` (now
|
||||
reading `col`/`row`/`colSpan`/`rowSpan` — an old `x`/`y`/`width`/`height` blob throws
|
||||
in the try/catch and falls back to `defaultFor`, no migration code needed, as
|
||||
predicted), an unchanged-in-spirit `defaultFor`, and the new `nextFreeSlot` scan.
|
||||
- `lib/src/hud/hud_layout_controller.dart` rewritten: `updatePosition`/`updateSize`
|
||||
take ints, clamp, and reject-on-collision (no-op, no revert needed since state is
|
||||
never mutated until the candidate passes); `setVisible` calls `nextFreeSlot` only
|
||||
when the metric's own slot now collides with another visible widget.
|
||||
- `lib/src/ui/components/draggable_resizable_hud_widget.dart` rewritten: local
|
||||
`_dragOffset`/`_resizeDelta` pixel state tracks the live gesture smoothly; snapping
|
||||
to the nearest grid cell and calling `onMoved`/`onResized` exactly once happens on
|
||||
`onLongPressEnd`/`onPanEnd`. Both offsets reset to zero right after that call
|
||||
regardless of whether the controller accepted the move, which is what makes a
|
||||
rejected move/resize visually snap back with no separate accept/reject callback.
|
||||
Callback signatures changed to `void Function(int, int)`.
|
||||
- `lib/src/ui/components/hud_edit_overlay.dart`: the two callback closures updated to
|
||||
the new int signatures; no other change needed.
|
||||
- `lib/src/ui/record/record_screen.dart`'s `_HudMetricValue.build()`: wrapped in
|
||||
`FittedBox(fit: BoxFit.scaleDown)`, `maxLines`/`overflow` dropped from both `Text`s.
|
||||
|
||||
**Confirmed trade-off** (the one the ticket flagged in advance): `BoxFit.scaleDown`
|
||||
never enlarges past the reference size, so a widget resized to `hudMaxColSpan` x
|
||||
`hudMaxRowSpan` renders the same 10px/18px text as a 1x1 widget — just with more empty
|
||||
space around it, still centered via `DraggableResizableHudWidget`'s existing
|
||||
`Center`. Verified directly with the new "largest allowed size" widget test (a 4x3
|
||||
`DraggableResizableHudWidget` at 400x400 pixels records no overflow exception, same as
|
||||
the 1x1 case) — text-scaling-with-widget-size remains explicit future work, not a
|
||||
silent gap.
|
||||
|
||||
**Confirmed migration behavior**: an old-shaped saved layout (pre-this-ticket JSON with
|
||||
`x`/`y`/`width`/`height` keys) loads without crashing and falls back to `defaultFor`
|
||||
per metric — covered directly by a new `hud_widget_layout_test.dart` case and a new
|
||||
`config_test.dart` case using literal old-shaped JSON. No user-facing warning was
|
||||
added, per the ticket's own Risks section (no real user base yet to protect).
|
||||
|
||||
**Tests**: `test/hud_widget_layout_test.dart` and `test/hud_layout_controller_test.dart`
|
||||
were fully rewritten for the int grid fields, per the ticket's Tests section (JSON
|
||||
round trip, malformed/old-shaped-JSON fallback, `defaultFor` non-overlap and
|
||||
visibility, `clampedToGrid` edge/floor/ceiling/shrink-before-reposition cases,
|
||||
`hudRectsOverlap` touching/disjoint/containing/partial cases, `nextFreeSlot` colliding
|
||||
and empty/hidden-occupied cases, controller collision-rejection for both
|
||||
`updatePosition` and `updateSize`, and `setVisible`'s free-slot fallback). Also updated:
|
||||
`test/config_test.dart` (its `HudWidgetLayout` literal and JSON fixtures used the old
|
||||
field names — updated to the grid fields, plus one new case for old-shaped JSON) and
|
||||
`test/hud_edit_overlay_test.dart` (its `.x`/`.y` assertions became `.col`/`.row`; added
|
||||
the two ticket-requested widget tests for a collision-rejected drag and a
|
||||
collision-rejected resize, plus two more building `DraggableResizableHudWidget`
|
||||
directly at `1x1` and `hudMaxColSpan x hudMaxRowSpan` to assert `tester.takeException()`
|
||||
is `null` — the established no-overflow pattern already used in
|
||||
`settings_screen_test.dart`).
|
||||
|
||||
Final count: **392 tests passing** (up from the 374 baseline), `flutter analyze` clean.
|
||||
|
||||
Reference in New Issue
Block a user