T19/T21: map and export, completing Phase 4

flutter_map with the same OSM tiles and no-API-key reasoning that chose osmdroid.
All four load-bearing behaviours ported and, unlike the native app's map, tested:
one polyline per segment so a pause is a real gap, render-only decimation, the
zoom clamp at OSM's max tile zoom with a short-ride fallback, and a real user
agent. Speed colouring is bucketed per run rather than per-vertex, since neither
osmdroid nor flutter_map makes per-vertex paint reasonable.

Export via share_plus, which also handles the iPad popover anchor a naive port
forgets. It passes the raw stored points, never the map's decimated path.

164 tests passing, analyze clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 16:27:42 -05:00
parent bcc12b314f
commit d501528e69
20 changed files with 1085 additions and 478 deletions

View File

@@ -49,8 +49,9 @@ final recordingEngineProvider = Provider<RecordingEngine>((ref) {
});
/// The live speedo feed, published from the fix callback at GPS rate.
final liveTelemetryProvider =
Provider<LiveTelemetry>((ref) => LiveTelemetry.instance);
final liveTelemetryProvider = Provider<LiveTelemetry>(
(ref) => LiveTelemetry.instance,
);
// --- Reactive state ---------------------------------------------------------
@@ -70,3 +71,9 @@ final recorderStateProvider = StreamProvider<RecorderState>((ref) {
final engine = ref.watch(recordingEngineProvider);
return engine.stateStream;
});
/// Whether the trip-detail map renders.
///
/// Kept as a toggle from v2: the map must only ever be live on a visible screen, and no
/// tile is fetched while recording in the background.
final mapEnabledProvider = StateProvider<bool>((ref) => true);