FB-04: fix Route Planner map failing to render on cold navigation
routePlanProvider's AsyncLoading state collapsed with "route doesn't exist" via .valueOrNull, so a brand-new route's screen briefly rendered "This route no longer exists." with no FlutterMap in the tree before the DB stream's first emission arrived. Add a hasValue guard mirroring waypointsAsync's existing pattern, and replace the route planner's hardcoded initialZoom of 14 with FB-01's ambientZoom constant for street-level parity with the rest of the app.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# FB-04 — Fix Route Planner's map failing to render + match street-level zoom
|
||||
|
||||
**Depends on** FB-01 (reuses its `ambientZoom` constant) · **Size** M · **Status** Not started
|
||||
**Depends on** FB-01 (reuses its `ambientZoom` constant) · **Size** M · **Status** Done
|
||||
|
||||
## Goal
|
||||
The Route Planner screen's map doesn't render at all for the user. Find the real cause
|
||||
@@ -214,3 +214,61 @@ far past street level, exactly matching the "same zoomed in map view" ask.
|
||||
Closed-loop routes (FB-05, sequenced after this ticket since it also edits this file
|
||||
heavily). Turn-by-turn route following (V3-09, already explicitly deferred by UI-06).
|
||||
Any change to `RoutesListScreen` itself.
|
||||
|
||||
## Outcome
|
||||
|
||||
The ticket's high-confidence root-cause hypothesis was confirmed exactly as written, no
|
||||
surprises in investigation. `FB-01`'s `ambientZoom` constant was already present in
|
||||
`lib/src/ui/components/ride_map.dart` (line 54) when this ticket started, so no
|
||||
fallback definition was needed.
|
||||
|
||||
**Root cause**, confirmed by reproduction: `route` was read via
|
||||
`ref.watch(routePlanProvider(widget.routeId)).valueOrNull`, which collapses "stream
|
||||
still loading" and "route doesn't exist" into the same `null`. On a cold navigation to
|
||||
a brand-new route (fresh `StreamProvider.autoDispose.family` instance, DB stream not
|
||||
yet emitted), this made the screen render "This route no longer exists." with zero
|
||||
`FlutterMap` in the tree for a route that was completely valid — exactly matching the
|
||||
user's "doesn't work at all" report. `waypointsAsync` already had the correct
|
||||
`hasValue` guard right next to it; `route` simply never got the same treatment.
|
||||
|
||||
Reproduced first via a widget test (no real emulator available/reliable in this
|
||||
environment): `repo.createRoutePlan(...)` followed by `pumpWidget` with **no**
|
||||
additional pump — asserting immediately after the very first frame — reliably showed
|
||||
the "no longer exists" text and zero `FlutterMap` widgets, confirming the bug. The same
|
||||
test, run again after applying the fix (and separately, reverted before the fix to
|
||||
confirm it fails on the old code), passed once `routeAsync.hasValue` guards the
|
||||
transition, matching the ticket's `Design`/`Implementation` sections precisely:
|
||||
- `route` was changed to hold the full `AsyncValue<RoutePlan?>` (`routeAsync`), with a
|
||||
new `if (!routeAsync.hasValue)` branch returning a spinner-only `Scaffold`, mirroring
|
||||
`waypointsAsync`'s existing pattern two lines below.
|
||||
- `route = routeAsync.value` is read only after that guard passes, and the existing
|
||||
"no longer exists" branch (for a genuinely missing/deleted route) is otherwise
|
||||
unchanged.
|
||||
- `ambientZoom` was added to this file's `ride_map.dart` `show` clause, and
|
||||
`initialZoom: waypoints.length <= 1 ? 14 : maxTileZoom - 3` became
|
||||
`initialZoom: waypoints.length <= 1 ? ambientZoom : maxTileZoom - 3`.
|
||||
|
||||
No investigation steps 3-5 (debugPrint state tracing, checking
|
||||
`cachedTileProviderProvider`'s null-tileProvider fallback, diffing tile URL setup
|
||||
against `RideMap`) were needed — the primary hypothesis fully explained the reported
|
||||
symptom on the first reproduction attempt, and step 5's `tileUrlTemplate`/
|
||||
`tileSubdomains`/etc. are already imported from the same `ride_map.dart` export
|
||||
`RideMap` uses, so no stale-URL-style regression was present.
|
||||
|
||||
Two new regression tests were added to `test/route_planner_screen_test.dart`:
|
||||
1. A brand-new route's screen is pumped with no settling: asserts the loading spinner
|
||||
shows and neither the "no longer exists" text nor `FlutterMap` appear on that first
|
||||
frame, then asserts the real map appears once both streams resolve. Verified this
|
||||
test fails against the pre-fix code (assertion on the spinner/text) and passes after
|
||||
the fix.
|
||||
2. A route with zero waypoints is asserted to open at `MapOptions.initialZoom ==
|
||||
ambientZoom` (17.0), not the old hardcoded `14`. Verified this test fails against
|
||||
the pre-fix code and passes after the fix.
|
||||
The existing "a missing route says so instead of a blank map" test (using
|
||||
`pumpAndSettle`) continues to pass unchanged, confirming the fix doesn't weaken the
|
||||
genuinely-deleted/never-existed case.
|
||||
|
||||
**Final state**: `flutter analyze` clean (4 pre-existing `info`-level issues in
|
||||
unrelated files — `crash_reporter.dart`, `map_connectivity.dart` — present on `main`
|
||||
before this ticket, untouched by this change). `flutter test`: **404 passing** (402
|
||||
baseline + 2 new regression tests), zero failures, zero regressions.
|
||||
|
||||
Reference in New Issue
Block a user