From 8946955f76b5075d16f5a2b2730d87d83f84831f Mon Sep 17 00:00:00 2001 From: qguillaume Date: Wed, 6 May 2026 23:17:22 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20passage=20du=20filtre=20date=20=C3=A0?= =?UTF-8?q?=20une=20s=C3=A9lection=20de=20p=C3=A9riode=20(DateRange)=20dan?= =?UTF-8?q?s=20l'historique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/features/history/history_screen.dart | 103 ++++++++++++++--------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/lib/features/history/history_screen.dart b/lib/features/history/history_screen.dart index 17e2de56..4418d291 100644 --- a/lib/features/history/history_screen.dart +++ b/lib/features/history/history_screen.dart @@ -21,7 +21,9 @@ class _HistoryScreenState extends State { List _sessions = []; bool _isLoading = true; TargetType? _filterType; - DateTime? _selectedDate; // --- AJOUT : Variable pour le filtre date --- + + // --- MODIFICATION : Remplacement de DateTime par DateTimeRange --- + DateTimeRange? _selectedDateRange; @override void initState() { @@ -30,25 +32,42 @@ class _HistoryScreenState extends State { } Future _loadSessions() async { + if (!mounted) return; setState(() => _isLoading = true); + try { final repository = context.read(); - // On récupère toutes les sessions. Le filtrage visuel se fera dans la liste - // ou tu peux adapter ton repository pour accepter un DateTime. final sessions = await repository.getAllSessions(targetType: _filterType); if (mounted) { setState(() { _sessions = sessions; - if (_selectedDate != null) { - _sessions = _sessions - .where( - (s) => - s.createdAt.year == _selectedDate!.year && - s.createdAt.month == _selectedDate!.month && - s.createdAt.day == _selectedDate!.day, - ) - .toList(); + + // --- LOGIQUE DE FILTRAGE PAR PÉRIODE --- + if (_selectedDateRange != null) { + _sessions = _sessions.where((s) { + // On compare uniquement les dates (sans les heures) pour éviter les bugs + 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; }); @@ -66,17 +85,31 @@ class _HistoryScreenState extends State { } } - // --- AJOUT : Fonction DatePicker --- - Future _pickDate() async { - final DateTime? picked = await showDatePicker( + // --- MODIFICATION : Fonction DateRangePicker --- + Future _pickDateRange() async { + final DateTimeRange? picked = await showDateRangePicker( context: context, - initialDate: _selectedDate ?? DateTime.now(), + initialDateRange: _selectedDateRange, firstDate: DateTime(2020), - lastDate: DateTime.now(), + lastDate: DateTime.now().add(const Duration(days: 1)), locale: const Locale('fr', 'FR'), + builder: (context, child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: ColorScheme.dark( + primary: AppTheme.primaryColor, + onPrimary: Colors.white, + surface: Theme.of(context).cardColor, + onSurface: Colors.white, + ), + ), + child: child!, + ); + }, ); + if (picked != null) { - setState(() => _selectedDate = picked); + setState(() => _selectedDateRange = picked); _loadSessions(); } } @@ -103,7 +136,6 @@ class _HistoryScreenState extends State { ), ], ), - // --- MODIFICATION : Utilisation d'une Column pour fixer le bas --- body: Column( children: [ Expanded( @@ -113,23 +145,22 @@ class _HistoryScreenState extends State { ? _buildEmptyState() : _buildContent(), ), - _buildBottomFilterBar(), // --- AJOUT : La barre de filtre en bas --- + _buildBottomFilterBar(), ], ), ); } - // --- AJOUT : Widget de la barre du bas --- Widget _buildBottomFilterBar() { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Theme.of(context).cardColor, - boxShadow: [ + boxShadow: const [ BoxShadow( - color: Colors.black12, + color: Colors.black26, blurRadius: 4, - offset: const Offset(0, -2), + offset: Offset(0, -2), ), ], ), @@ -139,23 +170,20 @@ class _HistoryScreenState extends State { children: [ Expanded( child: OutlinedButton.icon( - onPressed: _pickDate, - icon: const Icon(Icons.calendar_today, size: 18), + onPressed: _pickDateRange, + icon: const Icon(Icons.date_range, size: 18), label: Text( - _selectedDate == null - ? 'Choisir une date' - : DateFormat( - 'dd MMMM yyyy', - 'fr_FR', - ).format(_selectedDate!), + _selectedDateRange == null + ? 'Choisir une période' + : '${DateFormat('dd/MM/yy').format(_selectedDateRange!.start)} - ${DateFormat('dd/MM/yy').format(_selectedDateRange!.end)}', ), ), ), - if (_selectedDate != null) + if (_selectedDateRange != null) IconButton( icon: const Icon(Icons.close, color: AppTheme.errorColor), onPressed: () { - setState(() => _selectedDate = null); + setState(() => _selectedDateRange = null); _loadSessions(); }, ), @@ -172,7 +200,7 @@ class _HistoryScreenState extends State { children: [ Icon(Icons.history, size: 64, color: Colors.grey[400]), const SizedBox(height: 16), - const Text('Aucune session trouvée'), + const Text('Aucune session sur cette période'), ], ), ); @@ -183,7 +211,7 @@ class _HistoryScreenState extends State { onRefresh: _loadSessions, child: CustomScrollView( slivers: [ - if (_sessions.length >= 2 && _selectedDate == null) + if (_sessions.length >= 2 && _selectedDateRange == null) SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(AppConstants.defaultPadding), @@ -211,7 +239,6 @@ class _HistoryScreenState extends State { ); } - // Les fonctions _openSessionDetail et _deleteSession restent identiques à ton code original void _openSessionDetail(Session session) async { await Navigator.push( context, @@ -250,7 +277,7 @@ class _HistoryScreenState extends State { await repository.deleteSession(session.id); _loadSessions(); } catch (e) { - // ... snackbar d'erreur + debugPrint('Erreur suppression: $e'); } } }