Stage 5: History, the shared daily Streak and Reminders

- Streak computed from all complete Sessions: Grace Hour (00:00-01:00
  counts for yesterday unless it is done), a Freeze per 7 Streak Days
  (max 2) spent automatically on a missed day (ADR 0006)
- Top bar flame (grey until today is done) opening a panel with current
  and longest Streak, Freezes and a month calendar; 'Day N of your
  streak' on a fresh summary
- History per Mode grouped by day, reopening each summary
- Two adjustable Reminders (19:00, 22:30) scheduled 14 days ahead with
  flutter_local_notifications, none on a done day; permission asked
  after the first complete Session or from Settings
- Settings: Reminders, the Player chime, exercise credits

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CedricandClaude Opus 5.5 committed 2026-10-29 00:34:49 +01:00
1 parent 971ff64117
commit 1ffe6269ea
31 files changed
+1972 -50

No files matched your search

+15 -1
View File
@@ -12,6 +12,7 @@ void main() {
late PlanRepository plans;
late SessionRepository sessions;
late FakePlayerEffects effects;
late FakeNotifier notifier;
setUp(() {
final db = testDatabase();
@@ -19,13 +20,21 @@ void main() {
plans = PlanRepository(db);
sessions = SessionRepository(db);
effects = FakePlayerEffects();
notifier = FakeNotifier();
});
Future<void> startPlan(WidgetTester tester, Mode mode, List<PlanItem> items) async {
final plan = await plans.create(mode, 'Routine');
await plans.save(plan.copyWith(items: items));
usePhoneScreen(tester);
await pumpApp(tester, plans: plans, sessions: sessions, effects: effects, prefs: {'mode': mode.name});
await pumpApp(
tester,
plans: plans,
sessions: sessions,
effects: effects,
notifier: notifier,
prefs: {'mode': mode.name},
);
await tester.tap(find.byTooltip('Start'));
await tester.pump();
await tester.pump();
@@ -66,6 +75,11 @@ void main() {
await settle(tester);
expect(find.text('Session complete'), findsOneWidget);
await tester.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 50)));
await tester.pumpAndSettle();
expect(find.text('Day 1 of your streak'), findsOneWidget);
// The first finished Session is when Reminders ask for permission.
expect(notifier.permissionRequests, 1);
expect(effects.chimes, [Mode.stretching, Mode.stretching]);
expect(effects.screenOn, isFalse);
expect((await sessionsOf(tester, Mode.stretching)).single.complete, isTrue);