import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import '../../core/theme/app_theme.dart'; import '../../data/models/session.dart'; import '../../data/models/target_type.dart'; import '../../data/repositories/session_repository.dart'; import 'session_detail_screen.dart'; import 'widgets/session_list_item.dart'; import 'widgets/history_chart.dart'; class HistoryScreen extends StatefulWidget { final int refreshTick; const HistoryScreen({super.key, this.refreshTick = 0}); @override State createState() => _HistoryScreenState(); } class _HistoryScreenState extends State { List _sessions = []; bool _isLoading = true; TargetType? _filterType; DateTimeRange? _selectedDateRange; @override void initState() { super.initState(); _loadSessions(); } @override void didUpdateWidget(HistoryScreen oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.refreshTick != widget.refreshTick) { _loadSessions(); } } Future _loadSessions() async { if (!mounted) return; setState(() => _isLoading = true); try { final repository = context.read(); final sessions = await repository.getAllSessions(); if (mounted) { setState(() { _sessions = sessions; if (_filterType != null) { _sessions = _sessions .where((s) => s.analyses.any((a) => a.targetType == _filterType)) .toList(); } if (_selectedDateRange != null) { _sessions = _sessions.where((s) { final sessionDate = DateTime( s.createdAt.year, s.createdAt.month, s.createdAt.day, ); final startDate = DateTime( _selectedDateRange!.start.year, _selectedDateRange!.start.month, _selectedDateRange!.start.day, ); final endDate = DateTime( _selectedDateRange!.end.year, _selectedDateRange!.end.month, _selectedDateRange!.end.day, ); return sessionDate.isAtSameMomentAs(startDate) || sessionDate.isAtSameMomentAs(endDate) || (sessionDate.isAfter(startDate) && sessionDate.isBefore(endDate)); }).toList(); } _isLoading = false; }); } } catch (e) { if (mounted) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Erreur: $e'), backgroundColor: AppTheme.errorColor, ), ); } } } Future _pickDateRange() async { final picked = await showDateRangePicker( context: context, initialDateRange: _selectedDateRange, firstDate: DateTime(2020), lastDate: DateTime.now().add(const Duration(days: 1)), locale: const Locale('fr', 'FR'), ); if (picked != null) { setState(() => _selectedDateRange = picked); _loadSessions(); } } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( extendBody: true, appBar: AppBar( title: const Text('Carnet de Tir'), actions: [ IconButton( icon: Icon( Icons.date_range_outlined, color: _selectedDateRange != null ? AppTheme.primaryColor : null, ), tooltip: 'Filtrer par date', onPressed: _pickDateRange, ), const SizedBox(width: 8), ], ), body: Column( children: [ _buildFilterChips(isDark), Expanded( child: _isLoading ? const Center(child: CircularProgressIndicator()) : _sessions.isEmpty ? _buildEmptyState(isDark) : _buildContent(isDark), ), if (_selectedDateRange != null) _buildActivePeriodBanner(isDark), ], ), ); } Widget _buildFilterChips(bool isDark) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: isDark ? AppTheme.darkBackground : AppTheme.lightBackground, border: Border( bottom: BorderSide( color: isDark ? AppTheme.darkBorder : AppTheme.lightBorder, width: 1, ), ), ), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ _buildTypeFilterChip('Toutes les cibles', null), const SizedBox(width: 8), _buildTypeFilterChip( 'Cibles 1-10', TargetType.concentric, ), const SizedBox(width: 8), _buildTypeFilterChip( 'Silhouettes', TargetType.silhouette, ), ], ), ), ); } Widget _buildTypeFilterChip(String label, TargetType? type) { final isSelected = _filterType == type; return ChoiceChip( label: Text(label), selected: isSelected, onSelected: (selected) { if (selected) { setState(() => _filterType = type); _loadSessions(); } }, ); } Widget _buildActivePeriodBanner(bool isDark) { final start = DateFormat('dd/MM/yy').format(_selectedDateRange!.start); final end = DateFormat('dd/MM/yy').format(_selectedDateRange!.end); return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), decoration: BoxDecoration( color: isDark ? AppTheme.darkSurface : AppTheme.lightSurface, border: Border( top: BorderSide( color: isDark ? AppTheme.darkBorder : AppTheme.lightBorder, ), ), ), child: SafeArea( top: false, child: Row( children: [ const Icon(Icons.event, size: 18, color: AppTheme.primaryColor), const SizedBox(width: 8), Text( 'Période : $start - $end', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), const Spacer(), InkWell( onTap: () { setState(() => _selectedDateRange = null); _loadSessions(); }, borderRadius: BorderRadius.circular(6), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: Row( children: [ Text( 'Effacer', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: AppTheme.errorColor, ), ), const SizedBox(width: 4), const Icon(Icons.close, size: 14, color: AppTheme.errorColor), ], ), ), ), ], ), ), ); } Widget _buildEmptyState(bool isDark) { return Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: isDark ? AppTheme.darkSurface : AppTheme.lightSurfaceVariant, shape: BoxShape.circle, border: Border.all( color: isDark ? AppTheme.darkBorder : AppTheme.lightBorder, ), ), child: Icon( Icons.history_toggle_off, size: 56, color: isDark ? AppTheme.darkTextMuted : AppTheme.lightTextMuted, ), ), const SizedBox(height: 18), Text( 'Aucune session trouvée', style: TextStyle( fontSize: 17, fontWeight: FontWeight.w700, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), const SizedBox(height: 6), Text( _selectedDateRange != null || _filterType != null ? 'Essayez de réinitialiser vos filtres de recherche.' : 'Vos sessions enregistrées apparaîtront ici.', textAlign: TextAlign.center, style: TextStyle( fontSize: 13, color: isDark ? AppTheme.darkTextSecondary : AppTheme.lightTextSecondary, ), ), ], ), ), ); } Widget _buildContent(bool isDark) { return RefreshIndicator( onRefresh: _loadSessions, color: AppTheme.primaryColor, child: CustomScrollView( slivers: [ if (_sessions.length >= 2 && _selectedDateRange == null) SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: HistoryChart(sessions: _sessions), ), ), SliverPadding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 100), sliver: SliverList( delegate: SliverChildBuilderDelegate( (context, index) { final session = _sessions[index]; return SessionListItem( session: session, onTap: () => _openSessionDetail(session), onDelete: () => _deleteSession(session), ); }, childCount: _sessions.length, ), ), ), ], ), ); } void _openSessionDetail(Session session) async { await Navigator.push( context, MaterialPageRoute(builder: (_) => SessionDetailScreen(session: session)), ); _loadSessions(); } Future _deleteSession(Session session) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Supprimer la session'), content: Text( 'Voulez-vous supprimer définitivement la session du ${DateFormat('dd/MM/yyyy à HH:mm').format(session.createdAt)} ?', ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Annuler'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom( backgroundColor: AppTheme.errorColor, foregroundColor: Colors.white, ), child: const Text('Supprimer'), ), ], ), ); if (confirmed == true && mounted) { try { final repository = context.read(); await repository.deleteSession(session.id); _loadSessions(); } catch (e) { debugPrint('Erreur suppression: $e'); } } } }