Add UI-09: monochrome dark map tiles

Today's OSM tiles are the default tan/cream basemap, which looks nothing like the mockups regardless of HUD styling. Recommends switching to CARTO's free Dark Matter raster tiles over a client-side color filter on OSM tiles, since the mockups depend on the map itself being dark, not just tinted.

Flags a real interaction with V3-11's offline tile cache: it's keyed by (z,x,y) with no provider tag, so switching tile sources without a cache-busting step would silently serve stale OSM tiles under CARTO's URL. That's folded into this ticket's implementation, not left as a followup bug.
This commit is contained in:
2026-08-23 18:29:59 -05:00
parent 822003ed38
commit 3e7878b6e1
2 changed files with 113 additions and 5 deletions

View File

@@ -0,0 +1,98 @@
# UI-09 — Monochrome dark map tiles
**Depends on** nothing · **Size** S · **Status** Not started
## Goal
Replace the tan/cream default OpenStreetMap raster style with a monochrome dark map, so
the map actually looks like it belongs in a dark-mode HUD instead of a light basemap
punched through a dark overlay.
## Context
`RideMap`, the Plan/Route Planning canvas, and every Stitch mockup all assume a dark or
near-monochrome map underneath the HUD. Today's `TileLayer` (`ride_map.dart`) points at
`tile.openstreetmap.org`, OSM's standard light/tan default style — the actual on-device
result is nothing like the mockups, regardless of how dark the chrome on top of it is.
This affects every screen that shows a map (Map HUD, Plan, Route Planning, and UI-01's
dimmed background on every other tab), so it's worth settling once, early, rather than
each screen ticket discovering the same mismatch independently.
## Design
Two real options, not one obvious answer:
**Option A — switch tile provider to CARTO's "Dark Matter" basemap.**
`https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png` (subdomains a-d, retina
`{r}` variant available, max native zoom 20). Purpose-built dark, desaturated/monochrome
cartography — closest to the mockups with the least engineering. Free for reasonable
usage same as OSM's own tiles, but it's a **different third party with its own usage
policy and attribution requirement** ("© OpenStreetMap contributors © CARTO", not just
OSM's own attribution) — a real dependency to add, not a style tweak.
**Option B — keep OSM tiles, apply a color filter client-side.** Wrap `TileLayer` in a
`ColorFiltered` widget using a `ColorFilter.matrix` that desaturates and inverts/darkens
the tan basemap into a monochrome dark look. No new third party, no new attribution, and
V3-11's offline tile cache keeps working against the exact tiles it already knows about
— but the result is a filtered light map, not tiles actually designed for dark
presentation, and will read as slightly "off" next to CARTO's purpose-built version
(road/building contrast tuned for light backgrounds doesn't always invert cleanly).
**Recommendation: Option A.** The mockups' whole aesthetic depends on the map itself
being dark, not just tinted dark, and CARTO's dark tiles are a well-established, free,
no-API-key option already widely used in the Flutter/Leaflet ecosystem for exactly this.
The added attribution line and a second host to trust are a small, one-time cost.
**V3-11 interaction:** the offline tile cache (`FileTileCache`/`CachedTileProvider`) is
already keyed by `TileKey(z, x, y)` with no provider-specific data baked in — but that
means a cache built against OSM tiles and a cache built against CARTO tiles are
**indistinguishable to the cache** despite being visually different. Switching providers
without a plan here would silently serve stale, wrong-looking cached OSM tiles once
CARTO's URL is live. This needs a cache-busting or provider-tagging fix as part of this
ticket, not a separate one — see Implementation.
## Implementation
1. Add a `provider`-qualified cache key (or a cache-version bump that invalidates
existing V3-11 cache contents wholesale) so switching tile sources can't silently
mix cached tiles from two visually different sources.
2. Update `RideMap`'s `TileLayer` (and the Route Planner's separate `TileLayer` instance
— see `route_planner_screen.dart`) to CARTO's dark tile URL template, correct
`subdomains`, and `maxNativeZoom: 20`.
3. Update the attribution requirement — check whether `flutter_map`'s
`RichAttributionWidget`/`AttributionWidget` is in use anywhere already, or add one;
OSM-only attribution is no longer sufficient once CARTO tiles are in the mix.
4. Update `tileUserAgent`/any OSM-specific comments in `ride_map.dart` that assumed OSM's
tile servers specifically (the "respect OSM's usage policy" reasoning still applies in
spirit to CARTO's own policy, but the specific server being addressed changes).
5. Re-verify V3-11's tile math/download flow still works end-to-end against the new URL
template (tile enumeration and caching are provider-agnostic already; only the fetch
URL construction needs updating).
## Acceptance criteria
- [ ] The map renders in a dark, desaturated/monochrome style matching the Stitch
mockups, not OSM's default tan basemap
- [ ] Correct attribution for both OpenStreetMap and CARTO is shown wherever the map is
shown
- [ ] Switching tile providers does not silently serve stale, visually-mismatched
cached tiles from before the switch (V3-11's cache is invalidated or
provider-tagged)
- [ ] Both `RideMap` and the Route Planner's independent `TileLayer` are updated
consistently — one dark style everywhere, not just on the screens that happened to
get touched first
## Tests
- Existing `ride_map`/route-planner widget tests updated for the new tile URL and still
passing
- Unit: cache-key/versioning change is exercised the same way V3-11's eviction tests
are — a cache built under the old scheme does not get served for the new provider
## Risks
- **A second third-party tile host is a real dependency, not a free color swap** — its
own usage policy, its own risk of being blocked if misused, and its own attribution
obligation. Treat it with the same care V3-11 already applies to OSM (rate-limit
respecting, no bulk prefetch, real user agent).
- If CARTO's free tier ever proves insufficient or is discontinued, Option B (a color
filter over OSM tiles) is the fallback with no new third-party dependency — worth
keeping in mind as a documented Plan B, not re-deriving from scratch later.
## Out of scope
A fully custom/self-hosted vector tile style — much larger scope, and not needed to hit
"looks like the mockups" today.