feat(train): Profile opens on your body, the last 12 weeks and this year (ADR 0030, D60)

Above the days: a card with your body's weight and resting and maximal
heart rate, tapped opening Your body; the last 12 weeks' time trained as
bars, a week tapped showing its time, distance and workouts; and this
calendar year by activity. Home's week card reads its time as the days do.

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-31 18:46:26 +01:00
commit 5cfab59bd2
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -29,6 +29,7 @@ import 'package:halkyon_train_flutter/src/feature/plan/model/plan.dart';
import 'package:halkyon_train_flutter/src/feature/plan/model/stored_plan.dart';
import 'package:halkyon_train_flutter/src/feature/profile/data/profile_repository.dart';
import 'package:halkyon_train_flutter/src/feature/profile/model/profile.dart';
import 'package:halkyon_train_flutter/src/feature/profile/widget/body_card.dart';
import 'package:halkyon_train_flutter/src/feature/profile/widget/profile_screen.dart';
import 'package:halkyon_train_flutter/src/feature/recording/data/announce_store.dart';
import 'package:halkyon_train_flutter/src/feature/recording/data/device_store.dart';
@ -44,6 +45,7 @@ import 'package:halkyon_train_flutter/src/feature/route/data/routing_gateway.dar
import 'package:halkyon_train_flutter/src/feature/route/model/route.dart';
import 'package:halkyon_train_flutter/src/feature/workout/data/workout_repository.dart';
import 'package:halkyon_train_flutter/src/feature/workout/model/workout.dart';
import 'package:halkyon_train_flutter/src/feature/workout/widget/progress_cards.dart';
import 'package:halkyon_train_flutter/src/feature/workout/widget/week_card.dart';
import 'package:halkyon_train_flutter/src/tabs/maps_tab.dart';
import 'package:halkyon_train_flutter/src/tabs/record_tab.dart';
@ -661,6 +663,65 @@ void main() {
expect(find.text('52'), findsOneWidget);
expect(find.text('Female'), findsOneWidget);
});
testWidgets("Profile's card shows the figures given, opens Your body, and "
'follows a change (D60)', (tester) async {
await tester.runAsync(
() => profile.save(
const ProfileContent(
weightKg: 72.5,
restingHeartRate: 52,
maxHeartRate: 188,
),
),
);
await start(tester, usedBefore: true, profile: profile);
await goTab(tester, 'Profile');
await tester.runAsync(pumpEventQueue);
await tester.pump();
final card = find.byType(BodyCard);
expect(
find.descendant(
of: card,
matching: find.text('72.5 kg · resting 52 bpm · max 188 bpm'),
),
findsOneWidget,
);
await tester.runAsync(
() => profile.save(const ProfileContent(restingHeartRate: 50)),
);
await tester.runAsync(pumpEventQueue);
await tester.pump();
expect(
find.descendant(of: card, matching: find.text('resting 50 bpm')),
findsOneWidget,
);
await tester.tap(card);
await tester.pumpAndSettle();
expect(find.text('50'), findsOneWidget);
});
testWidgets("without figures, Profile's card says what they're for", (
tester,
) async {
await start(tester, usedBefore: true, profile: profile);
await goTab(tester, 'Profile');
await tester.runAsync(pumpEventQueue);
await tester.pump();
expect(
find.descendant(
of: find.byType(BodyCard),
matching: find.text(
'What your band and your heart-rate zones work from',
),
),
findsOneWidget,
);
});
});
group('the Polar Loop (ADR 0030, D34, D35)', () {
@ -3143,6 +3204,52 @@ void main() {
});
});
testWidgets('Profile charts the last 12 weeks, this week chosen, a week '
'tapped showing its own, and sums up the year by activity (D60)', (
tester,
) async {
tester.platformDispatcher.localesTestValue = const [Locale('en', 'GB')];
addTearDown(tester.platformDispatcher.clearLocalesTestValue);
// Saturday, 31 October 2026.
await withClock(Clock.fixed(DateTime(2026, 10, 31, 15)), () async {
await saveRun(DateTime(2026, 10, 27, 7, 30));
await saveRow();
await saveRun(DateTime(2026, 9, 3, 18));
await startWith(tester);
await goTab(tester, 'Profile');
final weeks = find.byType(WeeksCard);
Finder inWeeks(String text) =>
find.descendant(of: weeks, matching: find.text(text));
expect(inWeeks('Last 12 weeks'), findsOneWidget);
expect(inWeeks('This week'), findsOneWidget);
// 12:30 running and 30:00 rowing.
expect(inWeeks('42 min · 2.50 km · 2 workouts'), findsOneWidget);
await tester.tap(find.bySemanticsLabel('Week of 31 Aug'));
await tester.pump();
expect(inWeeks('Week of 31 Aug'), findsOneWidget);
expect(inWeeks('12 min · 2.50 km · 1 workout'), findsOneWidget);
final year = find.byType(YearCard);
expect(
find.descendant(of: year, matching: find.text('2026')),
findsOneWidget,
);
double top(String text) => tester
.getTopLeft(find.descendant(of: year, matching: find.text(text)))
.dy;
expect(top('Rowing indoors'), lessThan(top('Running')));
expect(
find.descendant(
of: year,
matching: find.text('2 workouts · 25 min · 5.00 km'),
),
findsOneWidget,
);
});
});
testWidgets("a workout's page shows its map, totals, splits and charts, "
'and where the map comes from', (tester) async {
await saveRun(DateTime(2026, 10, 27, 7, 30));