Skip to content

VeloSpot v1.0.22

Choose a tag to compare

@github-actions github-actions released this 21 Jun 21:16
e895b18

VeloSpot v1.0.22

Added

  • Ride heatmap overlay β€” a new Ride heatmap map layer turns your recorded rides into a colour heatmap that reveals where you cycle most. All recorded GPS tracks are aggregated into a compact grid (β‰ˆ11 m cells) weighted by how often you've ridden through each spot, so frequently used streets glow hotter (cool blue β†’ red). Toggle it in Layers; it's off by default and persisted, sits beneath the map pins (which stay tappable), and is built/aggregated off the main thread. The pure aggregation logic (RideHeatmap) is unit-tested and the overlay reuses the existing recorded-ride data, so no extra storage is needed. Fully localised across all eight supported languages (MapLayerCategory.HEATMAP, updateHeatmapLayer).
  • Spoken turn-by-turn voice guidance (TTS) β€” navigation can now read the upcoming-turn instructions aloud via Android TextToSpeech, building on the existing on-screen turn banner. It speaks an early prepare cue when a turn comes within ~150 m ("In 150 m, turn left"), a final imminent cue within ~30 m ("Now turn left") and an arrival cue at the destination; each cue fires once per turn (re-arming after you pass it), and off-route situations are suppressed until a reroute lands. A new "Voice guidance" switch in the Settings sheet (Appearance & map) toggles it β€” disabled by default (opt-in) and persisted across sessions. The decision logic (NavigationVoiceCues) is pure and unit-tested, the engine wrapper (NavigationVoiceGuide) matches the app locale and uses navigation-guidance audio attributes, and the flag lives in VoiceGuidancePreferences. Fully localised across all eight supported languages.
  • "Route hilliness" slider β€” flatter offline routes on demand β€” the offline Routing Profile sheet now carries a discrete Route hilliness slider with five steps (Any β†’ Gentle β†’ Flatter β†’ Low climb β†’ Flattest) that lets you trade a bit of distance for less climbing. Each step maps to an extra uphill penalty (ElevationPreference.uphillExtraCost) handed to BRouter as a uniform uphill_extra profile parameter, which is added on top of every bundled profile's own uphill cost β€” so Any leaves routing unchanged and flatter levels progressively avoid ascents. The choice is persisted (OfflineRoutingPreferences.getElevationPreference) and applied to point-to-point, on-demand and round-trip routing; changing it while navigating immediately recomputes the active route. Offline (BRouter) only β€” the online OSRM fallback has no elevation model and ignores it. The uphill_extra parameter was added to all five profiles (trekking, fastbike, mtb, gravel, shortest, PROFILES_VERSION 4 β†’ 5) and is parse-checked by BRouterProfileIntegrityTest; the levelβ†’cost mapping is covered by ElevationPreferenceTest. Fully localised across all eight supported languages.

Fixed

  • No profile starts the route on the sidewalk anymore β€” opening navigation on the pavement was possible in two ways, both now closed for every bundled profile (PROFILES_VERSION 4 β†’ 8): (1) the start-snapping guard (check_start_way + noStartWay=footway,sidewalk) was only in trekking/gravel, so fastbike/mtb/shortest could snap the start onto a footway=sidewalk β€” it's now declared in all five; and (2) cycling a footway=sidewalk was cheaper than the parallel carriageway in several profiles, so the route hugged the pavement: trekking/shortest rode a bicycle-allowed sidewalk almost for free, and the MTB profile (which heavily penalises paved roads) made even a plain sidewalk cheaper than a residential/tertiary road. A footway=sidewalk surcharge now keeps every profile on the carriageway (the MTB surcharge is large enough to beat its high road cost). A regression test (BRouterNoStartWayProbeTest) asserts every profile both populates noStartWays and prices a sidewalk above a tertiary road.
  • Round trips now work with every cycling profile β€” generating a Round trip with a profile that enables consider_elevation / consider_forest / consider_river (trekking, fastbike, mtb) silently produced no route ("route data incomplete"). With no explicit start heading, BRouter derived one via getRandomDirectionFromData, which for those profiles reads area-info data and parses a dummy.brf that VeloSpot doesn't bundle. The round-trip generator now always hands BRouter a concrete start direction (a random heading when the rider doesn't pick one), bypassing that path entirely so loops build for every profile (BRouterEngine.calculateRoundTrip, regression-guarded by BRouterRoundTripDirectionTest).
  • Offline routing no longer fails when the start-U-turn correction can't reroute β€” the standstill second pass (which re-runs BRouter with a forced forward direction to drop a spurious start hairpin) used to overwrite the valid first-pass route, so if BRouter couldn't satisfy the forced direction (one-way nets, dead-ends) the whole request failed with "route data incomplete". The second pass is now best-effort: its result is only adopted when it actually produces a route, otherwise the good first-pass route is kept (BRouterEngine.calculateRoute).
  • Offline routing with "Any" hilliness no longer breaks on some profiles β€” selecting Any used to send routing down a different BRouter code path (no key-value injection, a different profile-cache key) than the other levels, which left some profiles (e.g. gravel) unable to produce a route on Any while every other setting worked. The uphill_extra parameter is now always passed as a key-value map β€” Any simply carries a zero penalty β€” so every hilliness level uses the identical, working path (BRouterEngine.elevationKeyValues, guarded by BRouterProfileIntegrityTest).

πŸ“₯ APK Variants

File Description
VeloSpot-v1.0.22.apk F-Droid flavor – no Google services, ready to sideload; this is the APK F-Droid reproducibly verifies
VeloSpot-v1.0.22-googlePlay.apk Google Play flavor – includes Google Play Services Location

Installation (sideload)

  1. Download the APK below.
  2. On your Android device: Settings β†’ Apps β†’ Install unknown apps β†’ allow your browser or file manager.
  3. Open the APK and tap Install.

The F-Droid flavor is also available on F-Droid.