ReviewOS

stacks/wildloop

Heart rate: pick a source and make it real

#1010
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Problem

Nothing in the app has ever produced a heart rate, and 50f4c2e removed the tile that promised one. Real support is still worth having — it is a core Strava field and the one most visible on an activity page next to distance and pace.

What is missing today:

  • No column. activities has no heart-rate field of any kind.
  • No source. The GPX / TCX / FIT importer does not read HR out of a file, and the recorder has no strap or watch input.
  • Every writer hardcodes null — useRecorder, useActivityImport, useManualActivity and useActivityCatalog all set heartRateAvg: null, heartRateMax: null.

The type fields survive in stores.stx and the composables, so the shape is already there for whatever fills it.

The decision this needs first

Where the number comes from, because each option has a different cost and reaches a different set of people.

1. GPX / TCX / FIT extensions — cheapest. Garmin, COROS and Suunto exports all carry HR in track-point extensions (<gpxtpx:hr> in GPX, <HeartRateBpm> in TCX, a record field in FIT). The importer already walks every track point, so this is a parse and a column. Covers anyone importing from another watch, which is also the migration path off Strava.

2. HealthKit / Health Connect read — medium. settings.stx already connects to Apple Health and reads steps, distance and active energy. Adding a workout-scoped heart-rate read is a fourth getData and putting heartRate back in the authorization list, which 50f4c2e deliberately removed. Note the test in tests/unit/health-permissions.test.ts fails on a requested-but-unread scope, so it would have to be read at the same time it is asked for.

3. Live capture from a strap — most work. Web Bluetooth for the web recorder, native BLE for the app, plus a per-sample HR series and the storage that implies.

(1) is the obvious start: it needs no permission, no device support and no native work, and it is the one that helps somebody bringing their history across.

Work

  • Decide the source, or the order of sources
  • Migration: average and max heart rate on activities
  • Parse HR from imported files, if (1)
  • Persist through ActivityStoreAction, return from index and show
  • Restore the tile on the activity page, and show it only when a value exists
  • A per-sample series if a chart is wanted later — decide now whether the column is a summary or a track

Not this

Putting the tile back without a source. It printed an em dash on every activity ever saved, which reads as broken rather than as absent.

Sign in to comment on this issue.