3 Commits

Author SHA1 Message Date
82f07a2d68 Use the real Rippr icons instead of the Flutter defaults
Launcher, notification and launch screen on both platforms, all generated from
the native app's design sources rather than redrawn.

Android uses the adaptive icon files verbatim from the native app: foreground,
monochrome and the #101418 background colour. That matters because the adaptive
foreground draws its ring at r=32, the corrected radius that survives the
launcher's circular mask -- the first native version used r=43 and the mask
cropped the ring clean off.

iOS gets the full-bleed r=43 artwork instead, which is right there: iOS applies a
rounded superellipse rather than a circle crop, so the wider ring fits. All 15
sizes rendered from the SVG, and the 1024 verified to have no alpha channel,
which the App Store rejects.

The notification icon is ic_stat_rippr, a white silhouette on transparency.
Android masks status bar icons to a solid shape, so pointing this at the colour
launcher icon would render a featureless white blob.

Launch screens were the generated white, which flashes before a dark app on every
cold start. Both now use the app's own tarmac colour with the route mark centred.

Verified on the Android emulator rather than assumed: the launcher shows the
route mark with its orange accent intact, resource 0x7f07007c resolves to
drawable/ic_stat_rippr, and the notification reads "Rippr is recording" with a
clean silhouette. The run also recorded 23 points into a real trip -- the first
time this port has captured anything on Android.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 01:30:41 -05:00
ee3ef74331 T12-T14: platform liveness via geolocator; drop flutter_foreground_task
geolocator_android's ForegroundNotificationConfig raises a service with
foregroundServiceType=location and holds a wake lock for as long as the position
stream is subscribed, and the plugin declares that service in its own manifest.
That covers everything the native TrackingService used a foreground service and
a PARTIAL_WAKE_LOCK for, so flutter_foreground_task is gone -- and with it both
deprecation warnings that were recorded under T01.

Known parity gap for T27: geolocator's notification cannot carry actions, so the
native Pause/Resume buttons in the shade are not reproduced.

iOS: UIBackgroundModes plus allowBackgroundLocationUpdates keep the isolate and
the writer timer alive while updates flow. Two settings matter more than they
look -- pauseLocationUpdatesAutomatically is false because CoreLocation does not
reliably restart, and activityType is otherNavigation rather than
automotiveNavigation, which would snap fixes to the road network and silently
falsify the recorded path. Usage strings are specific, not generic.

Android deliberately does not request ACCESS_BACKGROUND_LOCATION: a foreground
service with a visible notification is exactly the supported case, and asking
would trigger the harder "Allow all the time" flow for no benefit.

T14 process-death resume is implemented and called at startup, covered by four
tests including the 111 km crash-gap guard.

Verified by building both platforms and launching on the iOS simulator: Drift
opened, Riverpod resolved, restore found no active trip, controls correct.
lib/main.dart is a harness so the pipeline can be exercised on hardware before
Phase 4 builds screens; T15 replaces it.

Phase 3 done: 145 tests passing, analyze clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 12:14:37 -05:00
725e6f63b7 Scaffold Flutter port: toolchain, project, and Geo
T00 — toolchain green on both platforms. flutter doctor reports no issues.
Pinned Flutter to Temurin 21 (AGP rejects the default JDK 25, same constraint
as the native build) and installed Android cmdline-tools with an explicit
--sdk_root, the trap already documented in the native DEVELOPMENT.md.
No caches were deleted: the 16 GiB disk reading that drove the cleanup plan
re-measured at 36 GiB before anything was removed.

T01 — flutter create for android+ios. applicationId is com.rippr.port, not
com.rippr, so the native app stays installable alongside it during the port;
T27 switches it at cutover.

T02 — geo/geo.dart ported from com.rippr.geo.Geo with all 23 tests, tolerances
and comments carried over unchanged. Kotlin's object namespace became top-level
functions; LatLon stays our own type so the pure layer never depends on
flutter_map.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 20:13:15 -05:00