Files
ZenXercise/lib/src/app.dart
T
CedricandClaude Opus 5.5 1ffe6269ea 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>
2026-10-29 00:34:49 +01:00

62 lines
2.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart';
import 'design/app_theme.dart';
import 'design/zen_style.dart';
import 'exercises/views/exercise_detail_view.dart';
import 'home/home_view.dart';
import 'localization/app_localizations.dart';
import 'plans/views/exercise_picker_view.dart';
import 'plans/views/plan_editor_view.dart';
import 'player/views/player_view.dart';
import 'player/views/summary_view.dart';
import 'settings/settings_controller.dart';
import 'settings/settings_view.dart';
class ZenXerciseApp extends StatelessWidget {
const ZenXerciseApp({super.key});
@override
Widget build(BuildContext context) {
final mode = context.watch<SettingsController>().mode;
// The whole app morphs into the new Mode at that Mode's own pace.
final style = ZenStyle.forMode(mode);
return MaterialApp(
theme: AppTheme.forMode(mode),
themeAnimationDuration: style.motion,
themeAnimationCurve: style.curve,
restorationScopeId: 'app',
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
onGenerateTitle: (context) => AppLocalizations.of(context).appTitle,
// Status bar icons follow the Mode's ground on every screen, with or without an app bar.
builder: (context, child) => AnnotatedRegion<SystemUiOverlayStyle>(
value: style.brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
child: child!,
),
onGenerateRoute: (settings) => MaterialPageRoute<Object?>(
settings: settings,
builder: (context) => switch (settings.name) {
ExerciseDetailView.routeName => ExerciseDetailView(exerciseId: settings.arguments! as String),
PlanEditorView.routeName => PlanEditorView(planId: settings.arguments! as String),
ExercisePickerView.routeName => ExercisePickerView(planId: settings.arguments! as String),
PlayerView.routeName => PlayerView(planId: settings.arguments! as String),
SummaryView.routeName => switch (settings.arguments) {
final SummaryArguments a => SummaryView(sessionId: a.sessionId, justFinished: a.justFinished),
final id => SummaryView(sessionId: id! as String),
},
SettingsView.routeName => const SettingsView(),
_ => const HomeView(),
},
),
);
}
}