diff --git a/RIPPR.md b/RIPPR.md index d9c6147..ad2bd47 100644 --- a/RIPPR.md +++ b/RIPPR.md @@ -4,7 +4,7 @@ Rippr is a native Android GPS ride recorder for motorcycles. Its canonical repo `~/dojo/rippr`, which **has no git remote** — it exists only on that machine, so the bundle below is the only off-machine copy of its history. -**Snapshot taken at:** `957392f` — "v3: add Ideas section, reverse the no-live-map decision" (20 commits) +**Snapshot taken at:** `d418920` — "v3: add waypoint route planning; record that handlebar mounting changes the premise" (21 commits) ## What is here diff --git a/rippr-full-history.bundle b/rippr-full-history.bundle index ea73d73..2112fd0 100644 Binary files a/rippr-full-history.bundle and b/rippr-full-history.bundle differ diff --git a/rippr-src/README.md b/rippr-src/README.md index 7f5e088..bd49dfd 100644 --- a/rippr-src/README.md +++ b/rippr-src/README.md @@ -25,7 +25,7 @@ Kotlin 2.0.21 AGP 8.7.3 Gradle 8.11.1 | Rename / delete / merge rides | Working | | GPX + GeoJSON export | Working, validated against an external parser | | Upload to a REST endpoint | Implemented, **no UI** — see below | -| Live map during recording | Deliberately absent — see below | +| Live map during recording | Absent in v2; planned for v3 | | Group ride view | Deferred to v3 | ## Quick start @@ -79,11 +79,13 @@ polylines, and GPX ``. Full reasoning in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). -## Two deliberate absences +## Deliberate absences -**No live map while recording.** The phone is in a pocket; nobody is looking at it. A live -map would burn battery on top of GPS and a wake lock for nothing. The map is a post-ride -artifact, gated behind a toggle, and `TrackingService` holds no reference to any map type. +**No live map while recording** — *superseded, see [docs/v3/BACKLOG.md](docs/v3/BACKLOG.md).* +v2 shipped without one because the phone rides in a pocket, so a live map would burn battery +for something nobody is looking at. That premise no longer holds: handlebar mounting is now +a wanted use case. The constraint that survives is architectural — `TrackingService` holds +no reference to any map type, and rendering belongs to a visible screen's Compose lifecycle. **No UI for the upload endpoint.** The REST uploader works and is tested, but is only reachable via `Config.setUploadEndpoint()`. It has no server to talk to yet; the UI arrives diff --git a/rippr-src/docs/v3/BACKLOG.md b/rippr-src/docs/v3/BACKLOG.md index 2db2a05..79c882a 100644 --- a/rippr-src/docs/v3/BACKLOG.md +++ b/rippr-src/docs/v3/BACKLOG.md @@ -67,14 +67,25 @@ brings hosting, privacy, and location-sharing consent into scope. ## 3. Live map on the recording screen — **decision reversed** v2 deliberately shipped no live map, on the reasoning that the phone rides in a pocket. -Dylan has since asked for one anyway, for visual appeal. Treat the v2 stance as superseded. +Dylan has since asked for one — for visual appeal, and because **people may mount the phone +on the handlebars** to watch the route live. Treat the v2 stance as superseded. -What still holds and should not be given up: +**The handlebar case changes the premise, not just the feature.** v1 and v2 were both built +around "start it, pocket it, stop it". A mounted phone is a different product with different +constraints, and it is worth deciding explicitly whether that becomes a first-class mode: + +- **Screen on for the whole ride** — battery goes from "a background service" to "a + service plus a lit screen plus continuous map rendering". Measure before committing. +- **Sunlight legibility** — the current dark theme is chosen for glanceability, but daylight + behind a visor is a different problem. +- **Glove-sized targets** — already partly handled (72dp buttons); a map needs the same care. +- **Keep-screen-awake** handling, and what happens on a call or notification. + +What still holds regardless: - **`TrackingService` must never reference a map.** Rendering belongs to the Compose lifecycle of a visible screen, not the service. -- **Screen-on only.** No tile fetch or redraw while backgrounded. -- Battery cost sits on top of GPS and a wake lock — worth measuring before and after. +- **No tile fetch or redraw while backgrounded**, even in mounted mode. --- @@ -111,6 +122,14 @@ Terse on purpose. Unshaped, to be consolidated later. elevation smoothing. - **Paid cloud backup.** Ongoing storage of rides over time. Needs accounts first, plus a decision on hosting, pricing, and what happens to data when someone stops paying. +- **Waypoint route planning.** Drop a series of pins on the map to "draw" a route, get + distance and estimates back, and save it to ride later. This is *pre*-ride planning — + a genuinely new mode alongside recording, not an extension of it. Needs its own entity + (`Route` + `Waypoint`), separate from `Trip`, since a plan is not a recording. + Straight-line pin-to-pin distance is easy and reuses `Geo.haversineMeters`; snapping to + actual roads needs a routing service (OSRM, GraphHopper, Valhalla — self-hostable) and is + a much larger step. Natural follow-ons: follow a planned route on the live map, and + compare a recorded ride against the plan afterwards. ### Threads running through these @@ -119,6 +138,11 @@ identity, and a privacy stance. Worth scoping together rather than separately. Activity type and theming are independent and much cheaper — either could ship alone. +Live map, handlebar mounting and waypoint following also cluster: all three assume a +visible screen during the ride, and all three want the same map component. Route planning +is the odd one out — it needs no ride in progress at all and could be built entirely +standalone. + --- ## 6. Things that must not regress