Full UI redesign pass complete: persistent tab shell with an always-visible background map, Modern Professional Dark theme, monochrome dark map tiles, offline skeleton map, a shared GlassPanel/FloatingPill component kit, customizable HUD telemetry widgets, and the Map HUD / Plan & Route Planning / Rides History screen rebuilds. 374 tests passing, up from 316. The APK is a fresh release build (debug-signed, no release signing config exists yet). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Xki7YAcc2TiN2PRZJ2tXr
171 lines
11 KiB
Markdown
171 lines
11 KiB
Markdown
# UI-06 — Plan & Route Planning redesign
|
|
|
|
**Depends on** UI-01, UI-03 · **Size** M · **Status** Done
|
|
|
|
## Goal
|
|
Rebuild the Plan tab (empty state) and the route planner (pins dropped) as fullscreen
|
|
map canvases with floating controls — correct in principle per the Stitch mockups, but
|
|
**restyled to match Map HUD (UI-05), not copied as-is** — see `README.md`'s note on why
|
|
these two mockups drifted from the design north star.
|
|
|
|
## Context
|
|
Today's `RoutePlannerScreen` is a `Scaffold` with an `AppBar` (title, rename/delete/
|
|
download actions) and the map beneath it. The mockups drop the header entirely (per
|
|
UI-01) and float everything — a pin-drop tooltip, a stat summary pill, a Start Route
|
|
button — over a fullscreen map, with a bottom nav bar instead of an app bar's back
|
|
button (the planner becomes a screen reached *within* the Plan tab, not a separately
|
|
titled pushed screen).
|
|
|
|
**What to take from the mockups as-is:** the fullscreen-map-plus-floating-controls
|
|
pattern, the pin-drop ripple micro-interaction, `PulsingLocationMarker` for the rider's
|
|
own position, the marching-ants animated route line, the floating stat pill
|
|
(Distance/Est. Time/Pins) replacing today's pre-download confirmation dialog as a
|
|
persistent readout instead of a one-time modal.
|
|
|
|
**What to restyle rather than copy:** icon fill-states, the nav bar's exact background/
|
|
blur treatment, and any color choice that doesn't match UI-08's actual palette as
|
|
established on the Map HUD screen. The Route Planning mockup specifically shows the
|
|
"Rides" nav icon active while viewing Plan — a generation error, not a real cross-tab
|
|
indicator; the shipped nav bar must correctly highlight whichever tab is actually active,
|
|
matching Map HUD's nav bar exactly (same widget, in fact — see UI-01).
|
|
|
|
## Design
|
|
- **Plan tab (no pins yet):** fullscreen map, technical grid overlay, floating "Tap to
|
|
drop a pin" tooltip (gentle float animation), `PulsingLocationMarker`.
|
|
- **Route Planning (pins dropped):** same canvas, plus the floating stat pill (`FloatingPill`
|
|
from UI-03) showing Distance / Est. Time / Pin count, updating live as pins are added/
|
|
moved/removed (already true of the underlying `RoutePlanRepository` data — this ticket
|
|
is presentation only). "Start Route" as a floating pill-shaped button above the nav
|
|
bar, replacing today's app-bar-driven actions.
|
|
- **Existing actions (rename, delete, download offline tiles)** need a new home now that
|
|
there's no app bar to hang icon buttons off of — a small floating overflow/glass menu
|
|
button is the natural fit, styled per Map HUD's `GlassPanel` language, not invented
|
|
fresh.
|
|
- **Drag-to-move / tap-to-delete pins:** unchanged interaction from today's
|
|
`RoutePlannerScreen`; only the chrome around it changes.
|
|
|
|
## Implementation
|
|
1. Rebuild `RoutePlannerScreen`'s `Scaffold`/`AppBar` as a headerless canvas within the
|
|
Plan tab's branch navigator (per UI-01), map at full opacity/interactivity here
|
|
(unlike the dimmed treatment other tabs get for the *background* map — this screen's
|
|
map *is* the primary content, same as Map HUD's).
|
|
2. Replace the pre-download confirmation dialog (V3-11) with the persistent `FloatingPill`
|
|
stat summary; keep the actual download flow (count/size check, cancellable progress)
|
|
as-is underneath — presentation change only.
|
|
3. Add the pin-drop ripple micro-interaction and marching-ants route line as new,
|
|
currently-nonexistent polish.
|
|
4. Rebuild the Plan tab's empty state (no `RoutePlan` selected/created yet) as the
|
|
fullscreen tooltip-and-map view, wired to whatever "create a new route" entry point
|
|
replaces today's `RoutesListScreen` FAB (see UI-07 — Rides History's tab likely
|
|
absorbs or sits alongside a route list; confirm final IA when that ticket lands, since
|
|
"Rides" and "Plan" may end up sharing more list/history UI than the current
|
|
`RoutesListScreen`/`TripsScreen` split assumes).
|
|
5. Move rename/delete/download actions to a floating glass menu, styled per Map HUD.
|
|
|
|
## Acceptance criteria
|
|
- [ ] Both Plan states (empty, pins dropped) render as fullscreen map canvases with no
|
|
header
|
|
- [ ] The nav bar on this screen is the exact same widget/styling as Map HUD's, with the
|
|
Plan tab correctly shown active (not the generation-error "Rides active" state
|
|
from the mockup)
|
|
- [ ] Existing pin add/move/delete, rename, delete-route, and offline-download behavior
|
|
all still work, restyled only
|
|
- [ ] Icon fill-states and colors match Map HUD, not the Stitch export's drifted values
|
|
|
|
## Tests
|
|
- All existing `route_planner_screen_test.dart` / `route_plan_repository_test.dart`
|
|
behavior tests still pass against the new presentation layer
|
|
- Widget: nav bar active-tab indicator is correct on this screen
|
|
- Widget: the floating stat pill updates live as pins are added/removed (already covered
|
|
conceptually by existing repository tests; add a presentation-level assertion that the
|
|
pill reflects it)
|
|
|
|
## Risks
|
|
- The IA question flagged in Implementation step 4 (how "create a new route" is reached
|
|
without a `RoutesListScreen`-style list-with-FAB) may turn out to need its own small
|
|
design decision once UI-07 is underway — don't block this ticket on it if the existing
|
|
entry point can be preserved with new styling in the meantime.
|
|
|
|
## Out of scope
|
|
Road-snapped routing (V3-08/V3-09, deferred). Any change to the underlying route-planning
|
|
data model or repository — this is presentation only.
|
|
|
|
## Outcome
|
|
|
|
**IA question (Risk section) resolved by deferring, as the ticket explicitly allowed:**
|
|
`RoutesListScreen` stays a list-with-`+`-button (the existing entry point), restyled with
|
|
`GlassPanel`-wrapped rows instead of plain `Card`s. The mockup's own "fullscreen map +
|
|
tooltip" language turned out, on close reading, to describe `RoutePlannerScreen`'s
|
|
*own* empty-pins state (the tooltip literally instructs "tap to drop a pin" — an action
|
|
that happens on the canvas, not on a list of named routes), not the routes list. Both
|
|
screens got the restyle their actual role calls for.
|
|
|
|
`RoutePlannerScreen` is now a headerless, full-opacity map canvas (its own map, not
|
|
UI-01's dimmed shell background — this screen's map *is* the primary content, matching
|
|
Map HUD). Implemented: the floating "TAP TO DROP A PIN" tooltip (`GlassPanel`, gentle
|
|
3s float) shown only while `waypoints.isEmpty`; `FloatingPill` (UI-03) showing Distance/
|
|
Est. Time/Pins once pins exist, replacing the old pre-download confirmation dialog's
|
|
role as the primary stat display (the confirmation dialog itself is untouched --
|
|
presentation only, per scope); a "START ROUTE" floating pill button; a `GlassPanel`
|
|
overflow menu (`PopupMenuButton`) holding Rename/Download offline tiles/Delete route,
|
|
replacing the removed `AppBar`'s actions row; and a pin-drop ripple micro-interaction
|
|
(a short-lived expanding-and-fading ring at the tap's local screen position).
|
|
|
|
**"Start Route," given real, working behaviour rather than shipped as a dead button:**
|
|
turn-by-turn following (V3-09) doesn't exist anywhere in the app to wire this to, and
|
|
inventing that data model here would violate this ticket's own "presentation only"
|
|
scope. Tapping it starts an ordinary recording and switches to the Map tab -- a real
|
|
action a rider can use today, not a placeholder.
|
|
|
|
**Est. Time honestly shows "--"** when `RoutePlan.estimatedMillis` is null (always, until
|
|
V3-08 adds road-snapped routing) rather than fabricating a straight-line estimate the
|
|
model doesn't back.
|
|
|
|
**Marching-ants route-line animation was deliberately dropped from scope.** It isn't in
|
|
this ticket's acceptance criteria (only the pin-drop ripple is named there), and
|
|
implementing it properly means animating a dash phase while continuously reprojecting
|
|
through `MapCamera.latLngToScreenOffset` under live pan/zoom -- real complexity for a
|
|
purely decorative effect. The existing static dashed polyline (already "visibly distinct
|
|
from a recorded path," the actual acceptance-relevant property) is unchanged.
|
|
|
|
**Bug found and fixed, unrelated to this ticket's own changes but discovered while
|
|
working in this file:** `_DownloadDialog`'s tile fetch still hardcoded
|
|
`https://tile.openstreetmap.org/...` directly -- a leftover from before UI-09 switched
|
|
the live map to CARTO's dark tiles. Downloading offline tiles would have silently cached
|
|
OSM's tan tiles under the same `(z, x, y)` keys UI-09's cache versioning was specifically
|
|
designed to keep separate from CARTO's, meaning a "successful" download would never
|
|
actually serve anything to the live dark map. Fixed to build the URL from the same
|
|
`tileUrlTemplate`/`tileSubdomains` every other tile fetch in the app already uses.
|
|
|
|
**Nav bar correctness:** no separate implementation needed -- `RoutePlannerScreen` is
|
|
pushed *within* the Plan branch's own navigator (UI-01's `StatefulShellBranch`
|
|
architecture), so the shell's persistent nav bar already shows Plan active automatically,
|
|
structurally ruling out the mockup's own "Rides active while viewing Plan" generation
|
|
error. Added a test asserting this directly rather than trusting the architecture alone.
|
|
|
|
**Tests:** `flutter analyze` clean. `flutter test` green at 370 tests. Updated every
|
|
existing `route_planner_screen_test.dart` assertion that referenced now-removed `AppBar`
|
|
structure (the `IconButton` keys are `PopupMenuItem`s behind the overflow menu now; there
|
|
is no app-bar title to assert renaming against, so that test now reads the repository
|
|
directly instead) plus one real test bug fixed along the way: two close-together
|
|
waypoints in the "tapping a pin deletes it" test happened to place one pin directly
|
|
under the new floating "Start Route" button in that test's fixed camera geometry, so the
|
|
tap intended for the pin actually hit the button underneath it (confirmed via
|
|
`WidgetController`'s own hit-test-mismatch warning, not assumed) -- reduced to a single
|
|
waypoint, which the camera centres exactly on, clear of the button. `PopupMenuButton`/
|
|
`PopupMenuItem` interactions needed bounded pumps rather than `pumpAndSettle`, same
|
|
reason the map's own tests already avoid it (a live `TileLayer` never goes idle in this
|
|
harness). Also fixed a real, unrelated bug the new `GlassPanel`-wrapped `ListTile` in
|
|
`RoutesListScreen` surfaced immediately: Flutter's own framework assertion that a
|
|
`ListTile` needs a `Material` ancestor to paint its ink splash correctly, which
|
|
`GlassPanel`'s `DecoratedBox` was sitting between it and -- fixed with a
|
|
`Material(type: MaterialType.transparency)` wrapper.
|
|
|
|
**Android emulator verification** (`Medium_Phone_API_35`): confirmed the empty-tooltip
|
|
state, dropping a pin (ripple visible, `FloatingPill` and "Start Route" appearing
|
|
immediately), and the overflow menu opening with all three actions -- all matching the
|
|
mockup and the Design section precisely. The Plan tab's nav-bar pill correctly followed
|
|
the active tab (a mid-transition-animation screenshot briefly looked wrong immediately
|
|
after tapping the tab; a screenshot taken a moment later confirmed it settles correctly
|
|
-- a timing artifact of screenshotting mid-animation, not a real bug).
|