import 'package:clock/clock.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import '../../design/page_header.dart'; import '../../design/zen_nav_bar.dart'; import '../../design/zen_style.dart'; import '../../localization/app_localizations.dart'; import '../../player/views/summary_view.dart'; import '../../settings/settings_controller.dart'; import '../../streak/day.dart'; import '../session_repository.dart'; /// The current Mode's finished Sessions by day, the latest first; each opens /// its summary again. class HistoryView extends StatelessWidget { const HistoryView({super.key}); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final mode = context.watch().mode; return StreamBuilder( stream: context.read().watchSessions(mode), builder: (context, snapshot) { final sessions = snapshot.data ?? const []; if (sessions.isEmpty) { return ListView( children: [ PageHeader(title: l10n.historyTitle), const SizedBox(height: 24), EmptyState(icon: Icons.history_rounded, title: l10n.historyEmptyTitle, body: l10n.historyEmptyBody), ], ); } final today = Day.of(clock.now()); final rows = [PageHeader(title: l10n.historyTitle)]; Day? shown; for (final session in sessions) { final day = Day.of(session.endedAt); if (day != shown) { shown = day; rows.add(_DayHeader(label: _dayLabel(l10n, day, today))); } rows.add( Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 10), child: _SessionTile(session: session), ), ); } return ListView( padding: EdgeInsets.only(bottom: ZenNavBar.height + 32 + MediaQuery.paddingOf(context).bottom), children: rows, ); }, ); } static String _dayLabel(AppLocalizations l10n, Day day, Day today) { if (day == today) return l10n.historyToday; if (day == today.add(-1)) return l10n.historyYesterday; final date = day.at(0, 0); return day.year == today.year ? DateFormat.MMMEd().format(date) : DateFormat.yMMMEd().format(date); } } class _DayHeader extends StatelessWidget { const _DayHeader({required this.label}); final String label; @override Widget build(BuildContext context) => Padding( padding: const EdgeInsets.fromLTRB(20, 8, 20, 8), child: Text(label, style: Theme.of(context).textTheme.titleSmall?.copyWith(color: ZenStyle.of(context).inkMuted)), ); } class _SessionTile extends StatelessWidget { const _SessionTile({required this.session}); final Session session; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final s = ZenStyle.of(context); final text = Theme.of(context).textTheme; final line = l10n.historySessionLine( DateFormat.Hm().format(session.endedAt), l10n.durationMinutes((session.duration.inSeconds / 60).round()), ); return Card( child: InkWell( onTap: () => Navigator.of(context).pushNamed(SummaryView.routeName, arguments: session.id), child: Padding( padding: const EdgeInsets.fromLTRB(16, 14, 12, 14), child: Row( children: [ Icon( session.complete ? Icons.check_circle_rounded : Icons.flag_rounded, color: session.complete ? s.accent : s.inkMuted, ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(session.planName, style: text.titleMedium, maxLines: 1, overflow: TextOverflow.ellipsis), const SizedBox(height: 2), Text(line, style: text.bodySmall?.copyWith(color: s.inkMuted)), ], ), ), if (!session.complete) Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: s.surfaceSoft, borderRadius: BorderRadius.circular(s.controlRadius.clamp(0, 12)), ), child: Text(l10n.historyEndedEarly, style: text.labelSmall?.copyWith(color: s.inkMuted)), ), ], ), ), ), ); } }