import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; import '../../../core/constants/env_config.dart'; import '../../../core/theme/theme_provider.dart'; import '../../../data/services/notification_service.dart'; import '../../../data/services/secure_storage.dart'; import '../../../domain/entities/notification.dart' as domain; import '../../widgets/custom_button.dart'; import '../../widgets/custom_snackbar.dart'; import '../../widgets/modern_empty_state.dart'; import '../../widgets/shimmer_loading.dart'; import '../event/event_screen.dart'; import '../friends/friends_screen.dart'; /// Écran des notifications avec design moderne et fonctionnalités complètes class NotificationsScreen extends StatefulWidget { const NotificationsScreen({super.key}); @override State createState() => _NotificationsScreenState(); } class _NotificationsScreenState extends State { @override void initState() { super.initState(); // Recharge les notifications au montage de l'écran WidgetsBinding.instance.addPostFrameCallback((_) { final notificationService = Provider.of(context, listen: false); notificationService.loadNotifications(); }); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return Consumer( builder: (context, notificationService, child) { final notifications = notificationService.notifications; final hasUnread = notifications.any((n) => !n.isRead); return Scaffold( appBar: AppBar( title: const Text('Notifications'), actions: [ if (hasUnread) TextButton.icon( onPressed: () => _markAllAsRead(notificationService), icon: const Icon(Icons.done_all), label: const Text('Tout marquer comme lu'), ), ], ), body: notificationService.isLoading ? const SkeletonList( itemCount: 5, skeletonWidget: ListItemSkeleton(), ) : notifications.isEmpty ? _buildEmptyState(context, theme, notificationService) : RefreshIndicator( onRefresh: () => notificationService.loadNotifications(), color: theme.colorScheme.primary, child: ListView.separated( padding: const EdgeInsets.all(16), physics: const AlwaysScrollableScrollPhysics(), itemCount: notifications.length, separatorBuilder: (context, index) => const Divider(), itemBuilder: (context, index) { final notification = notifications[index]; return _buildNotificationTile( context, theme, notification, notificationService, ); }, ), ), ); }, ); } Widget _buildEmptyState( BuildContext context, ThemeData theme, NotificationService notificationService, ) { return RefreshIndicator( onRefresh: () => notificationService.loadNotifications(), color: theme.colorScheme.primary, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: SizedBox( height: MediaQuery.of(context).size.height - 200, child: const ModernEmptyState( illustration: EmptyStateIllustration.notifications, title: 'Aucune notification', description: 'Vous serez notifié des nouvelles activités, événements et interactions avec vos amis', ), ), ), ); } Widget _buildNotificationTile( BuildContext context, ThemeData theme, domain.Notification notification, NotificationService notificationService, ) { return Dismissible( key: Key(notification.id), direction: DismissDirection.endToStart, background: Container( alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), decoration: BoxDecoration( color: theme.colorScheme.error, borderRadius: BorderRadius.circular(16), ), child: const Icon(Icons.delete, color: Colors.white), ), onDismissed: (direction) async { try { await notificationService.deleteNotification(notification.id); if (mounted) { context.showSuccess('Notification supprimée'); } } catch (e) { if (mounted) { context.showError('Erreur lors de la suppression'); } } }, child: ListTile( leading: CircleAvatar( backgroundColor: _getNotificationColor(theme, notification.type), child: Icon( _getNotificationIcon(notification.type), color: Colors.white, ), ), title: Text( notification.title, style: TextStyle( fontWeight: notification.isRead ? FontWeight.normal : FontWeight.bold, ), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 4), Text(notification.message), const SizedBox(height: 4), Text( _formatTimestamp(notification.timestamp), style: theme.textTheme.bodySmall, ), ], ), trailing: notification.isRead ? null : Container( width: 12, height: 12, decoration: BoxDecoration( color: theme.colorScheme.primary, shape: BoxShape.circle, ), ), onTap: () { _handleNotificationTap(notification, notificationService); }, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ); } Color _getNotificationColor(ThemeData theme, domain.NotificationType type) { switch (type) { case domain.NotificationType.event: return theme.colorScheme.primary; case domain.NotificationType.friend: return theme.colorScheme.secondary; case domain.NotificationType.reminder: return theme.colorScheme.tertiary; case domain.NotificationType.other: return theme.colorScheme.primary; } } IconData _getNotificationIcon(domain.NotificationType type) { switch (type) { case domain.NotificationType.event: return Icons.event; case domain.NotificationType.friend: return Icons.person_add; case domain.NotificationType.reminder: return Icons.alarm; case domain.NotificationType.other: return Icons.notifications; } } String _formatTimestamp(DateTime timestamp) { final now = DateTime.now(); final difference = now.difference(timestamp); if (difference.inDays > 7) { return 'Il y a ${difference.inDays ~/ 7} semaines'; } else if (difference.inDays > 0) { return 'Il y a ${difference.inDays} jour${difference.inDays > 1 ? 's' : ''}'; } else if (difference.inHours > 0) { return 'Il y a ${difference.inHours} heure${difference.inHours > 1 ? 's' : ''}'; } else if (difference.inMinutes > 0) { return 'Il y a ${difference.inMinutes} minute${difference.inMinutes > 1 ? 's' : ''}'; } else { return 'À l\'instant'; } } Future _handleNotificationTap( domain.Notification notification, NotificationService notificationService, ) async { // Marquer comme lue try { await notificationService.markAsRead(notification.id); } catch (e) { if (EnvConfig.enableDetailedLogs) { debugPrint('[NotificationsScreen] Erreur marquage lu: $e'); } } // Naviguer vers la page appropriée selon le type de notification if (!mounted) return; final secureStorage = SecureStorage(); final userId = await secureStorage.getUserId() ?? ''; switch (notification.type) { case domain.NotificationType.event: // Naviguer vers l'écran des événements // Si eventId est disponible, on pourrait naviguer vers les détails Navigator.push( context, MaterialPageRoute( builder: (context) => EventScreen( userId: userId, userFirstName: '', userLastName: '', profileImageUrl: '', ), ), ); break; case domain.NotificationType.friend: // Naviguer vers l'écran des amis if (userId.isNotEmpty) { Navigator.push( context, MaterialPageRoute( builder: (context) => FriendsScreen(userId: userId), ), ); } break; case domain.NotificationType.reminder: // Naviguer vers l'écran des événements Navigator.push( context, MaterialPageRoute( builder: (context) => EventScreen( userId: userId, userFirstName: '', userLastName: '', profileImageUrl: '', ), ), ); break; case domain.NotificationType.other: // Pas de navigation spécifique break; } } Future _markAllAsRead(NotificationService notificationService) async { try { await notificationService.markAllAsRead(); if (mounted) { context.showSuccess('Toutes les notifications ont été marquées comme lues'); } } catch (e) { if (mounted) { context.showError('Erreur: ${e.toString()}'); } } } }