Add Rippr source snapshot and full-history bundle

Two copies for two jobs. rippr-src/ is a browsable git archive export of
the tracked tree at 2f76983 - no build outputs, no local.properties, no
nested .git - which is convenient to read in gitea but carries no history
and will drift.

rippr-full-history.bundle is the real backup: all 18 commits, verified as
"records a complete history" and test-cloned before committing. This
matters because ~/dojo/rippr has no git remote and otherwise exists only
on one machine.

rippr-src/SNAPSHOT.md explains the difference and how to restore.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 08:30:25 -05:00
parent 4debdfa518
commit 280fd7f988
106 changed files with 10377 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
# T08 — Navigation shell + ViewModels
**Phase** 4 · **Depends on** T01 · **Status** Done
## Goal
Three navigable destinations, theme extracted out of the Activity, and state moved into
ViewModels. Done when Record, Trips, and Trip Detail are reachable with a working back
stack and `MainActivity` no longer owns screen state.
## Context
`app/src/main/java/com/rippr/MainActivity.kt` (216 lines) currently does everything:
permission launcher, service intents, theme definition, screen composition, and state.
That was proportionate for one screen and will not survive three.
Existing pieces to preserve rather than rewrite:
- The permission flow (`RequestMultiplePermissions`, with `POST_NOTIFICATIONS` added only
on TIRAMISU+) works and should move largely as-is.
- The battery-optimisation exemption prompt is genuinely useful for an app that must
survive a multi-hour ride; keep it on the Record screen.
- `RipprTheme` is currently a private composable applying `darkColorScheme()`. Dylan
called the UI "simple and clean" and explicitly likes it — **do not redesign it**.
Extract, do not restyle.
- `StatRow` and `BigStat` are reusable; move them into a shared `ui/components/`.
## Design
```
ui/
theme/ Theme.kt, Color.kt
components/ StatRow.kt, BigStat.kt, ConfirmDialog.kt
record/ RecordScreen.kt, RecordViewModel.kt
trips/ TripsScreen.kt, TripsViewModel.kt
detail/ TripDetailScreen.kt, TripDetailViewModel.kt
RipprNavHost.kt
```
Routes:
| Route | Screen |
|---|---|
| `record` | Start destination |
| `trips` | Trip list |
| `trip/{tripId}` | Detail, `tripId: Long` argument |
`navigation-compose` rather than hand-rolled state switching: the back stack from detail
→ list is worth not writing by hand, and it gives correct behaviour on the system back
gesture for free.
**ViewModels** get the repository through a simple factory — the app already uses a
`@Volatile` singleton for `AppDatabase` and T03 adds one for `TripRepository`. Hilt would
be more ceremony than a three-screen app earns.
**Navigation from Record → Trips** goes in a top bar action, keeping the Record screen's
centre free for the numeric readout.
## Implementation
1. Extract `ui/theme/` from `MainActivity`.
2. Move `StatRow` / `BigStat` into `ui/components/`, unchanged.
3. Create `RipprNavHost` with the three routes.
4. Add a ViewModel per screen with a shared factory.
5. Reduce `MainActivity` to: permissions, battery exemption, `setContent { RipprTheme { RipprNavHost() } }`.
6. Move service-intent dispatch into `RecordViewModel`.
## Acceptance criteria
- [x] All three destinations reachable; system back works from detail
- [x] `MainActivity` holds no screen state
- [x] Visual appearance of the Record screen is unchanged
- [x] Permission flow and battery-optimisation prompt still function
- [ ] Config change (rotation) does not lose state
> **Not verified.** The unchecked items above, and the Compose UI tests below, were
> not done. Verification for T08–T11 was manual on the emulator (screenshots through
> the full flow) plus the existing unit and instrumented suites. Compose UI tests are
> outstanding — tracked in T18.
## Tests
Instrumented Compose UI tests:
- Navigate record → trips → detail → back → back
- Rotation preserves screen state
- Existing suites stay green
## Risks / gotchas
- **Do not restyle.** The brief was "simple and clean, I like that". This task is
structural only.
- **`tripId` argument type.** Room ids are `Long`; declare `NavType.LongType` explicitly
or it silently arrives as a String.
- The v1 UI reads state via `collectAsStateWithLifecycle` already — keep that, it is the
correct choice over `collectAsState` for lifecycle-aware collection.
## Out of scope
Screen content beyond wiring (T09, T10, T11); any map (T13).