feat(train): a workout keeps its plan's steps as laps, shown on its page (ADR 0030, D43)

As a recording with a plan is saved, each step run becomes a lap in the
workout's sealed payload: the step, its round, when it started and ended,
its moving time and distance, with the highest heart rate the zones ran
with. The page lists the steps with their pace, speed or split, stroke
rate, watts and heart rate, marks whether each held its target, and the
charts shade the work steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-28 23:12:34 +01:00
commit e1304975d6
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -1250,7 +1250,8 @@ void main() {
});
testWidgets('a plan chosen on the Record sheet chooses its activity, goes '
'to the recorder spoken, and its step shows with Lap (D42)', (
'to the recorder spoken, its step shows with Lap (D42), and the '
'workout keeps its steps (D43)', (
tester,
) async {
final plans = PlanRepository(MemoryPlanGateway(), keys);
@ -1317,6 +1318,31 @@ void main() {
await tester.tap(find.text('Lap'));
await pass(tester);
expect(platform.laps, 1);
// The service ends the step; saved, the workout keeps it (D43).
platform
..now = at.add(const Duration(seconds: 30))
..write('step @ 1')
..now = at.add(const Duration(seconds: 50));
await tester.longPress(find.text('Stop'));
await pass(tester);
await tester.tap(find.text('Save'));
await tester.runAsync(pumpEventQueue);
await pass(tester, 2);
final saved = (await tester.runAsync(workouts.all))!.single.content!;
expect(saved.plan?.name, 'Sprints');
expect(saved.plan?.laps.map((l) => l.step.kind), [
StepKind.work,
StepKind.recovery,
]);
await tester.tap(find.text('0:50'));
await tester.runAsync(pumpEventQueue);
await tester.pumpAndSettle();
expect(find.text('Steps of Sprints'), findsOneWidget);
expect(find.text('Work · 1 of 2'), findsOneWidget);
expect(find.text('30–35 km/h'), findsOneWidget);
expect(tester.takeException(), isNull);
});
});