import 'package:flutter/material.dart'; import '../../application/focus_seed_controller.dart'; import '../../l10n/l10n.dart'; import '../../models/focus_session.dart'; import '../../models/reflection_entry.dart'; import '../../widgets/seed_illustration.dart'; import '../../widgets/surface_panel.dart'; enum _HistoryView { focus, notes } class HistoryScreen extends StatefulWidget { const HistoryScreen({required this.controller, super.key}); final FocusSeedController controller; @override State createState() => _HistoryScreenState(); } class _HistoryScreenState extends State { _HistoryView _view = _HistoryView.focus; @override Widget build(BuildContext context) { final l10n = context.l10n; return Scaffold( appBar: AppBar(title: Text(l10n.historyTitle)), body: SafeArea( top: false, child: AnimatedBuilder( animation: widget.controller, builder: (context, _) { final state = widget.controller.state!; final focusSessions = state.sessions.reversed.toList(); final reflections = state.reflections.reversed.toList(); return ListView( padding: const EdgeInsets.fromLTRB(20, 8, 20, 28), children: [ _HistorySwitch( value: _view, onChanged: (value) => setState(() => _view = value), ), const SizedBox(height: 10), AnimatedSwitcher( duration: const Duration(milliseconds: 220), switchInCurve: Curves.easeOutCubic, switchOutCurve: Curves.easeInCubic, child: _view == _HistoryView.focus ? _FocusHistoryList( key: const ValueKey('focus-history'), sessions: focusSessions, onStartToday: () => Navigator.of(context).pop(), ) : _ReflectionHistoryList( key: const ValueKey('reflection-history'), reflections: reflections, onStartToday: () => Navigator.of(context).pop(), ), ), ], ); }, ), ), ); } } class _HistorySwitch extends StatelessWidget { const _HistorySwitch({required this.value, required this.onChanged}); final _HistoryView value; final ValueChanged<_HistoryView> onChanged; @override Widget build(BuildContext context) { final l10n = context.l10n; final scheme = Theme.of(context).colorScheme; return DecoratedBox( decoration: BoxDecoration( color: scheme.surfaceContainerLow.withValues(alpha: 0.70), borderRadius: BorderRadius.circular(16), border: Border.all( color: scheme.outlineVariant.withValues(alpha: 0.70), ), ), child: Padding( padding: const EdgeInsets.all(5), child: Row( children: [ Expanded( child: _HistorySwitchItem( selected: value == _HistoryView.focus, icon: Icons.timer_outlined, label: l10n.focusHistory, onTap: () => onChanged(_HistoryView.focus), ), ), const SizedBox(width: 6), Expanded( child: _HistorySwitchItem( selected: value == _HistoryView.notes, icon: Icons.edit_note_rounded, label: l10n.notesHistory, onTap: () => onChanged(_HistoryView.notes), ), ), ], ), ), ); } } class _HistorySwitchItem extends StatelessWidget { const _HistorySwitchItem({ required this.selected, required this.icon, required this.label, required this.onTap, }); final bool selected; final IconData icon; final String label; final VoidCallback onTap; @override Widget build(BuildContext context) { final theme = Theme.of(context); final scheme = theme.colorScheme; return Material( color: Colors.transparent, child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: AnimatedContainer( duration: const Duration(milliseconds: 180), curve: Curves.easeOutCubic, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), decoration: BoxDecoration( color: selected ? scheme.primary.withValues(alpha: 0.16) : Colors.transparent, borderRadius: BorderRadius.circular(12), boxShadow: selected ? [ BoxShadow( color: scheme.primary.withValues(alpha: 0.16), blurRadius: 12, offset: const Offset(0, 6), ), ] : null, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 19, color: selected ? scheme.primary : scheme.onSurfaceVariant, ), const SizedBox(width: 8), Flexible( child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: theme.textTheme.labelLarge?.copyWith( color: selected ? scheme.onSurface : scheme.onSurfaceVariant, fontWeight: selected ? FontWeight.w900 : FontWeight.w700, ), ), ), ], ), ), ), ); } } class _FocusHistoryList extends StatelessWidget { const _FocusHistoryList({ required this.sessions, required this.onStartToday, super.key, }); final List sessions; final VoidCallback onStartToday; @override Widget build(BuildContext context) { final l10n = context.l10n; if (sessions.isEmpty) { return _EmptyHistory( title: l10n.emptyFocusHistoryTitle, body: l10n.emptyFocusHistoryBody, tone: SeedIllustrationTone.archive, onStartToday: onStartToday, ); } return Column( children: [ for (var index = 0; index < sessions.length; index++) ...[ if (index > 0) const SizedBox(height: 8), _HistoryTimelineTile( leading: Icons.timer_outlined, title: l10n.focusMinutes(sessions[index].minutes), subtitle: localizedReadableDate( context, sessions[index].completedAt, ), trailing: localizedTime(context, sessions[index].completedAt), ), ], ], ); } } class _ReflectionHistoryList extends StatelessWidget { const _ReflectionHistoryList({ required this.reflections, required this.onStartToday, super.key, }); final List reflections; final VoidCallback onStartToday; @override Widget build(BuildContext context) { final l10n = context.l10n; if (reflections.isEmpty) { return _EmptyHistory( title: l10n.emptyNotesHistoryTitle, body: l10n.emptyNotesHistoryBody, tone: SeedIllustrationTone.data, onStartToday: onStartToday, ); } return Column( children: [ for (var index = 0; index < reflections.length; index++) ...[ if (index > 0) const SizedBox(height: 8), _HistoryTimelineTile( leading: reflections[index].mood.icon, title: reflections[index].note, subtitle: reflections[index].dateKey, ), ], ], ); } } class _EmptyHistory extends StatelessWidget { const _EmptyHistory({ required this.title, required this.body, required this.tone, required this.onStartToday, }); final String title; final String body; final SeedIllustrationTone tone; final VoidCallback onStartToday; @override Widget build(BuildContext context) { final theme = Theme.of(context); final scheme = theme.colorScheme; final minHeight = MediaQuery.sizeOf(context).height * 0.62; return SizedBox( height: minHeight.clamp(430, 620).toDouble(), child: Center( child: DecoratedBox( decoration: BoxDecoration( gradient: RadialGradient( center: Alignment.topCenter, radius: 1.1, colors: [ scheme.primary.withValues(alpha: 0.16), scheme.surfaceContainerLowest.withValues(alpha: 0.76), Colors.transparent, ], ), borderRadius: BorderRadius.circular(18), ), child: Padding( padding: const EdgeInsets.fromLTRB(18, 26, 18, 24), child: Column( mainAxisSize: MainAxisSize.min, children: [ SeedIllustration(size: 142, tone: tone, hero: true), const SizedBox(height: 16), Text( title, textAlign: TextAlign.center, style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w900, ), ), const SizedBox(height: 8), ConstrainedBox( constraints: const BoxConstraints(maxWidth: 310), child: Text( body, textAlign: TextAlign.center, style: theme.textTheme.bodyMedium?.copyWith( color: scheme.onSurfaceVariant, ), ), ), const SizedBox(height: 18), FilledButton.icon( onPressed: onStartToday, icon: const Icon(Icons.arrow_back_rounded), label: Text(context.l10n.navToday), ), ], ), ), ), ), ); } } class _HistoryTimelineTile extends StatelessWidget { const _HistoryTimelineTile({ required this.leading, required this.title, required this.subtitle, this.trailing, }); final IconData leading; final String title; final String subtitle; final String? trailing; @override Widget build(BuildContext context) { final theme = Theme.of(context); final scheme = theme.colorScheme; return SurfacePanel( padding: const EdgeInsets.fromLTRB(13, 12, 14, 12), borderColor: scheme.outlineVariant.withValues(alpha: 0.60), child: Row( children: [ DecoratedBox( decoration: BoxDecoration( color: scheme.primary.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(12), ), child: SizedBox.square( dimension: 42, child: Icon(leading, color: scheme.primary, size: 21), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, maxLines: 2, overflow: TextOverflow.ellipsis, style: theme.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w900, ), ), const SizedBox(height: 3), Text( subtitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: theme.textTheme.bodySmall?.copyWith( color: scheme.onSurfaceVariant, ), ), ], ), ), if (trailing != null) ...[ const SizedBox(width: 10), Text( trailing!, style: theme.textTheme.labelMedium?.copyWith( color: scheme.onSurfaceVariant, fontWeight: FontWeight.w800, ), ), ], ], ), ); } }