Files
bincio-rec/CLAUDE.md
T
Davide Scaini 9d82084fa1 feat: section 5 — MapLibre map with live track and camera follow
Replace SVG TrackView with a real MapLibre map:
- OpenFreeMap liberty tiles (no API key)
- Camera follows user in course mode while recording
- GeoJSONSource + LineLayer renders track polyline updated live
- UserLocation dot shows current GPS position
- Sensors button overlaid with semi-transparent background
2026-06-03 09:32:49 +02:00

6.4 KiB

bincio-rec

GPS activity recorder for the bincio ecosystem. Companion to bincio-autarchive (archive/sync app): rec makes the data, autarchive stores and syncs it.


Concept

A focused, minimal recording app for cycling, running, hiking, and walking. Records GPS track + BLE sensor data, saves to GPX, optionally uploads directly to a bincio-activity server. Future: live navigation / turn-by-turn instructions.

The app does one thing well: record. No browsing, no analysis — that's autarchive's job.


Ecosystem

bincio-rec          →  writes GPX files to shared storage
bincio-autarchive   →  imports GPX, stores locally, syncs to server
bincio-activity     →  server: parses GPX, stores activities, serves API
bincio-auth         →  auth service: issues JWTs for all bincio apps

bincio-rec can also upload directly to bincio-activity via /api/upload/raw (same endpoint autarchive uses), with instance URL + API token configured in settings.


Tech Stack

Expo Prebuild (not managed Expo, not bare RN).

  • Managed Expo ruled out: BLE requires native modules
  • Bare RN ruled out: Expo library ecosystem is valuable (location, notifications, file system)
  • Prebuild gives full native access while keeping Expo tooling and EAS Build

Key libraries:

  • expo-location + expo-task-manager — background GPS recording
  • react-native-ble-plx — BLE sensors (HR, power, cadence)
  • @maplibre/maplibre-react-native — live track map, future navigation
  • expo-notifications — km milestone alerts, future navigation cues
  • expo-keep-awake — keep screen on during recording (user-toggleable)
  • expo-file-system — write GPX/JSON to shared storage
  • expo-sqlite — local DB for past recordings list

Target: Android first, iOS second.


v1 Screens

  1. Sensor pairing — scan BLE, pair HR monitor / power meter / cadence sensor; persisted
  2. Recording — start / pause / resume / stop
    • Live stats: elapsed time, distance, current+avg speed, HR, power, cadence, elevation gain
    • Map with track drawn in real time
    • Keep-awake toggle
  3. Post-recording summary — stats overview, title field, save / discard
  4. Saved recordings — list of past sessions; tap to export GPX or upload to server
  5. Settings — bincio instance URL + API token; km notification toggle; upload format

Output Format

GPX with Garmin trackpoint extensions — one <trkpt> per second with:

  • lat/lon/elevation from GPS
  • <gpxtpx:hr> — heart rate
  • <gpxtpx:power> — power (watts)
  • <gpxtpx:cad> — cadence (rpm)

bincio-activity already parses this format via bincio.extract.parsers.

Files saved to a user-accessible location (iOS Files app / Android shared storage) so bincio-autarchive can import them manually.


Known Platform Concerns

  • Android battery optimization: aggressive OEMs (Xiaomi, Samsung, Huawei) kill background tasks. Prompt user to whitelist bincio-rec in battery settings on first launch. Every recording app has this problem — no framework-level fix.
  • iOS background location: requires location background mode in Info.plist and "Always" location permission. Fine for sideloading/TestFlight; App Store submission requires clear justification.
  • iOS foreground notifications: notification sounds are suppressed when app is in foreground — use expo-av audio cue instead for km alerts while screen is on.

Out of Scope (v1)

  • Navigation / turn-by-turn routing
  • Auto-pause (stop lights, etc.)
  • Structured workouts / intervals
  • Offline maps
  • Live tracking / sharing

v1 Completion Plan

Scaffold is done (all screens, navigation, store, services, GPX, DB, upload). Items below are what remains before v1 is shippable.

1 — Quick fixes

  • Keep-awake toggle — wired to keepAwake store state via activateKeepAwakeAsync / deactivateKeepAwake; toggle button visible in controls bar
  • Sensor button on Recording screen — " Sensors" button overlaid on map area navigates to SensorPairing modal
  • GPS pause/resumehandlePause calls stopGpsRecording(), handleResume calls startGpsRecording()
  • Track viewTrackView component renders recorded lat/lon points as a scaled SVG polyline on a dark background (no tile server needed); replaces the grey placeholder

2 — BLE

  • Android runtime permissionsrequestBlePermissions() requests BLUETOOTH_SCAN + BLUETOOTH_CONNECT on Android 12+ (API 31+) before scanning
  • Cadence CSC parsing — stateful parsing in parseCscMeasurement(): tracks previous crank revolution count + event time (uint16, 1/1024 s), computes RPM from delta with uint16 rollover handling
  • BLE persistencesavePairedDevice / loadPairedDevices / removePairedDevice in ble.ts via AsyncStorage; SensorPairingScreen shows saved sensors at top, auto-attempts reconnect on mount, Forget button removes a device

3 — Km notifications

  • Permission requestrequestNotificationPermissions() called in App.tsx on mount; foreground notification handler set at module level so iOS shows banners while app is active
  • Milestone tracker — module-level runningDistanceMeters / lastNotifiedKm / prevPoint in gps.ts, reset on each startGpsRecording(); each incoming location adds haversine distance and fires a notification when a new km is crossed, gated on the kmNotifications AsyncStorage setting

4 — Android battery optimization prompt

  • src/services/batteryOptimization.ts — Android-only, one-time prompt (dismissed flag in AsyncStorage); uses REQUEST_IGNORE_BATTERY_OPTIMIZATIONS intent to open the system dialog for bincio-rec directly; falls back to IGNORE_BATTERY_OPTIMIZATION_SETTINGS (general page) on OEMs that block the direct intent; called from App.tsx on mount alongside notification permission request

5 — Map

  • MapLibre basemapMap with OpenFreeMap liberty style (tiles.openfreemap.org); no API key required; logo and attribution hidden
  • Camera followCamera with trackUserLocation="course" while recording; switches off when idle/paused
  • Live track lineGeoJSONSource fed a memoized LineString from trackPoints; Layer with type="line" and blue stroke rendered on top of the basemap
  • User location dotUserLocation component shows current position on map