fix(mobile): nav-start crash + stale-origin + missing recenter FAB - #65
Merged
Conversation
Three coupled bugs in the navigation flow: 1. EXC_BREAKPOINT crash on session start (GlitchTip BEEBEEBIKE-APP-4): `Int(p.durationRemaining * 1000)` in Serialization.swift traps when ferrostar emits a non-finite duration on the first progress tick. Guard the FFI bridge against NaN/Inf/overflow on duration + distance fields, and against CLLocation's -1 sentinel for course (UInt16 init trap). Defense-in-depth: also filter bearing/speed/accuracy at the Dart layer in maplibreToUserLocation before they cross the boundary. 2. New routes started 20-30m back from current GPS. Geolocator's last-known cache lagged behind MapLibre's stream. Cache the live MapLibre fix in userLocationProvider (same source as the blue dot) and prefer it when seeding nav, picking route origins, or recentering after reroute. 3. Recenter FAB / compass never appeared during real-device nav. The first-fix transition was wired to ferrostar's snapped_location stream, which doesn't emit until well into the session. Drive the awaitingFirstFix → following transition off the cached MapLibre location at session start instead, with onUserLocationUpdated as the fallback. Renamed onFirstFix → onNavStart for clarity. Also bump iOS deployment target 13.0 → 16.0 (Podfile already declared 16.0; pbxproj had been stale and SPM device builds caught the mismatch where pod-only sim builds let it slide).
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three coupled bugs in the iOS navigation flow, all surfaced during a 20-minute real-device ride.
1. EXC_BREAKPOINT crash on nav start (GlitchTip BEEBEEBIKE-APP-4)
Int(p.durationRemaining * 1000)in Serialization.swift traps when ferrostar emits a non-finite duration on the first progress tick. GlitchTip captured the dict keyduration_remaining_msas the trap's value, pinpointing the line. Likely cause inside ferrostar:0/0from snapped speed=0 or a missing GraphHopper duration field. Root cause inside the Rust core not pursued — the FFI bridge shouldn't crash on degenerate input regardless.Guarded:
Int(durationRemaining * 1000)→ finite + bounded check (NaN/Inf/overflow → 0)UInt16(courseDeg)→ drop CLLocation's-1sentinel and out-of-range valuesDefense-in-depth:
maplibreToUserLocationin Dart also filters invalid bearing/speed/accuracy before they cross the boundary.2. New routes started 20-30m back from current GPS
Geolocator.getLastKnownPosition()reads the system-wide cache, which lags MapLibre's own location stream by up to half a minute at cycling speed. Added auserLocationProvider(StateProvider<UserLocation?>) populated from MapLibre'sonUserLocationUpdated— same source as the blue dot. Used as the preferred input when seeding nav, picking route origins (_handleMapTap,_navigateHome), and refreshing the preview after a reroute. Geolocator stays as a fallback for the cold-start case.3. Recenter FAB and compass never appeared during nav
The
awaitingFirstFix → followingtransition was wired to ferrostar'ssnapped_locationstream, which only emits once a tick lands. On real devices that didn't happen for the entire 20-minute ride, so the camera stayed inawaitingFirstFixand the FAB never rendered. Now driven off the cached MapLibre fix at session start (synchronously) withonUserLocationUpdatedas the fallback for the no-cache edge case. RenamedonFirstFix→onNavStartper design feedback ("first" was misleading mid-session).iOS deployment target 13.0 → 16.0
Podfilealready declared 16.0; pbxproj had been stale at 13.0. Pod-only sim builds let the mismatch slide, but SPM device-build resolution caught it (the ferrostar Swift Package requires.iOS(.v16)).Test plan
just test-mobile— 174 passing (3 new converter tests)just test-ferrostar-flutter-plugin— 21 passingflutter analyzecleanflutter build ios --simulator --no-codesignclean