import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../providers/supplement_provider.dart'; class HistoryScreen extends StatefulWidget { const HistoryScreen({super.key}); @override State createState() => _HistoryScreenState(); } class _HistoryScreenState extends State { int _selectedMonth = DateTime.now().month; int _selectedYear = DateTime.now().year; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().loadMonthlyIntakes(_selectedYear, _selectedMonth); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Intake History'), backgroundColor: Theme.of(context).colorScheme.inversePrimary, actions: [ IconButton( icon: const Icon(Icons.calendar_today), onPressed: _showMonthPicker, tooltip: 'Select Month', ), ], ), body: _buildCompactHistoryView(), ); } Widget _buildCompactHistoryView() { return Column( children: [ // Month selector header Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, border: Border( bottom: BorderSide( color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2), width: 1, ), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( onPressed: () { setState(() { if (_selectedMonth == 1) { _selectedMonth = 12; _selectedYear--; } else { _selectedMonth--; } }); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().loadMonthlyIntakes(_selectedYear, _selectedMonth); }); }, icon: const Icon(Icons.chevron_left), iconSize: 20, ), Text( DateFormat('MMMM yyyy').format(DateTime(_selectedYear, _selectedMonth)), style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Theme.of(context).colorScheme.onSurface, ), ), IconButton( onPressed: () { final now = DateTime.now(); if (_selectedYear < now.year || (_selectedYear == now.year && _selectedMonth < now.month)) { setState(() { if (_selectedMonth == 12) { _selectedMonth = 1; _selectedYear++; } else { _selectedMonth++; } }); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().loadMonthlyIntakes(_selectedYear, _selectedMonth); }); } }, icon: const Icon(Icons.chevron_right), iconSize: 20, ), ], ), ), // History list Expanded( child: Consumer( builder: (context, provider, child) { if (provider.monthlyIntakes.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.history, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant, ), const SizedBox(height: 16), Text( 'No intake history for this month', style: TextStyle( fontSize: 16, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), ); } // Sort intakes by date (most recent first) final sortedIntakes = List>.from(provider.monthlyIntakes) ..sort((a, b) => DateTime.parse(b['takenAt']).compareTo(DateTime.parse(a['takenAt']))); return ListView.builder( padding: const EdgeInsets.symmetric(vertical: 8), itemCount: sortedIntakes.length, itemBuilder: (context, index) { final intake = sortedIntakes[index]; final takenAt = DateTime.parse(intake['takenAt']); final units = (intake['unitsTaken'] as num?)?.toDouble() ?? 1.0; // Check if we need a date header final previousIntake = index > 0 ? sortedIntakes[index - 1] : null; final showDateHeader = previousIntake == null || DateFormat('yyyy-MM-dd').format(DateTime.parse(previousIntake['takenAt'])) != DateFormat('yyyy-MM-dd').format(takenAt); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (showDateHeader) ...[ Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text( DateFormat('EEEE, MMMM d').format(takenAt), style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Theme.of(context).colorScheme.primary, ), ), ), ], Dismissible( key: Key('intake_${intake['id']}'), direction: DismissDirection.endToStart, background: Container( alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), color: Colors.red.shade400, child: const Icon( Icons.delete, color: Colors.white, ), ), confirmDismiss: (direction) async { return await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Delete Intake'), content: Text('Delete ${intake['supplementName']} taken at ${DateFormat('HH:mm').format(takenAt)}?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('Cancel'), ), TextButton( onPressed: () => Navigator.of(context).pop(true), style: TextButton.styleFrom(foregroundColor: Colors.red), child: const Text('Delete'), ), ], ), ); }, onDismissed: (direction) { context.read().deleteIntake(intake['id']); }, child: Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 2), child: Card( margin: EdgeInsets.zero, elevation: 2, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: InkWell( onTap: () => _deleteIntake(context, intake['id'], intake['supplementName']), borderRadius: BorderRadius.circular(12), splashColor: Theme.of(context).colorScheme.primary.withValues(alpha: 0.4), highlightColor: Theme.of(context).colorScheme.primary.withValues(alpha: 0.3), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1), shape: BoxShape.circle, ), child: Icon( Icons.medication, color: Theme.of(context).colorScheme.primary, size: 18, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( intake['supplementName'], style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSurface, ), ), const SizedBox(height: 2), Text( '${DateFormat('HH:mm').format(takenAt)} • ${units.toStringAsFixed(units % 1 == 0 ? 0 : 1)} ${intake['supplementUnitType'] ?? 'units'}', style: TextStyle( fontSize: 11, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), if (intake['notes'] != null && intake['notes'].toString().isNotEmpty) ...[ const SizedBox(height: 2), Text( intake['notes'], style: TextStyle( fontSize: 11, fontStyle: FontStyle.italic, color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.8), ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ], ), ), Icon( Icons.delete_outline, size: 18, color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), ], ), ), ), ), ), ), ], ); }, ); }, ), ), ], ); } void _showMonthPicker() async { final now = DateTime.now(); final picked = await showDatePicker( context: context, initialDate: DateTime(_selectedYear, _selectedMonth), firstDate: DateTime(2020), lastDate: now, initialDatePickerMode: DatePickerMode.year, builder: (context, child) { return Theme( data: Theme.of(context).copyWith( dialogTheme: DialogThemeData( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), ), ), ), child: child!, ); }, ); if (picked != null) { if (!context.mounted) return; setState(() { _selectedMonth = picked.month; _selectedYear = picked.year; }); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().loadMonthlyIntakes(_selectedYear, _selectedMonth); }); } } void _deleteIntake(BuildContext context, int intakeId, String supplementName) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Delete Intake'), content: Text('Are you sure you want to delete this $supplementName intake?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), ElevatedButton( onPressed: () async { await context.read().deleteIntake(intakeId); if (!context.mounted) return; Navigator.of(context).pop(); // Force refresh of the UI setState(() {}); // Force refresh of the current view data WidgetsBinding.instance.addPostFrameCallback((_) { context.read().loadMonthlyIntakes(_selectedYear, _selectedMonth); }); final sonner = ShadSonner.of(context); final id = DateTime.now().millisecondsSinceEpoch; sonner.show( ShadToast( id: id, title: Text('$supplementName intake deleted'), action: ShadButton( size: ShadButtonSize.sm, child: const Text('Dismiss'), onPressed: () => sonner.hide(id), ), ), ); }, style: ElevatedButton.styleFrom(backgroundColor: Colors.red), child: const Text('Delete'), ), ], ), ); } @override void dispose() { super.dispose(); } }