feat(train): the heart-rate strap, recorded by the service itself (ADR 0030, D25-D27)
The Record sheet gains a Heart rate row: a sheet looks for straps advertising the Heart Rate Service, the nearest first, once nearby devices are allowed, and the one chosen is remembered in the person's folder; it records with every workout unless switched off for one. The recorder service connects to it with Android's own Bluetooth API, no package (D26), parses Heart Rate Measurement in Kotlin (tested on the JVM), writes each rate and the strap's state to the recording file, and asks for a lost strap again for as long as it records. The recording screen shows the heart rate, and "Strap lost" while it is gone; a workout's page shows the heart's average and highest rate, each split's average and its chart. iOS's recording waits for a Mac (D25), after the rower. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
405577050d
commit
de5fd43e06
1 changed files with 1782 additions and 42 deletions
|
|
@ -12,6 +12,7 @@ class FakeRecorderPlatform({
|
|||
RecorderPermission.location,
|
||||
RecorderPermission.notifications,
|
||||
RecorderPermission.activity,
|
||||
RecorderPermission.bluetooth,
|
||||
},
|
||||
}) implements RecorderPlatform {
|
||||
/// What was asked for, each time.
|
||||
|
|
@ -19,7 +20,22 @@ class FakeRecorderPlatform({
|
|||
|
||||
/// How each recording was started.
|
||||
final started =
|
||||
<({String path, Activity activity, AutoPauseBy? autoPause})>[];
|
||||
<
|
||||
({
|
||||
String path,
|
||||
Activity activity,
|
||||
AutoPauseBy? autoPause,
|
||||
String? strap,
|
||||
})
|
||||
>[];
|
||||
|
||||
/// The straps nearby, seen as soon as a scan starts, and whether
|
||||
/// Bluetooth is on.
|
||||
List<FoundStrap> nearby = [];
|
||||
bool bluetoothOn = true;
|
||||
|
||||
/// How many scans were started.
|
||||
int scans = 0;
|
||||
|
||||
/// The notices shown, the first one the start's.
|
||||
final notices = <RecorderNotice>[];
|
||||
|
|
@ -55,8 +71,14 @@ class FakeRecorderPlatform({
|
|||
required Activity activity,
|
||||
required AutoPauseBy? autoPause,
|
||||
required RecorderNotice notice,
|
||||
String? strap,
|
||||
}) async {
|
||||
started.add((path: path, activity: activity, autoPause: autoPause));
|
||||
started.add((
|
||||
path: path,
|
||||
activity: activity,
|
||||
autoPause: autoPause,
|
||||
strap: strap,
|
||||
));
|
||||
notices.add(notice);
|
||||
_file = File(path)
|
||||
..writeAsStringSync(
|
||||
|
|
@ -102,4 +124,14 @@ class FakeRecorderPlatform({
|
|||
_file!.readAsLinesSync().forEach(controller.add);
|
||||
return controller.stream;
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<FoundStrap> scanStraps() {
|
||||
scans++;
|
||||
if (!bluetoothOn) {
|
||||
return Stream.error(BluetoothOff());
|
||||
}
|
||||
// Open until cancelled, as a scan is.
|
||||
return Stream.multi((listener) => nearby.forEach(listener.add));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue