import 'dart:async'; import 'package:flutter/material.dart'; import '../../data/services/realtime_notification_service.dart'; /// Widget qui écoute les streams de notifications et affiche des toasts. /// /// Ce widget doit wrapper l'application pour avoir accès au BuildContext /// et pouvoir afficher les notifications visuelles (SnackBar, Dialog, etc.). /// /// **Usage :** /// ```dart /// MaterialApp( /// home: RealtimeNotificationHandler( /// realtimeService: _realtimeService, /// child: HomeScreen(), /// ), /// ); /// ``` class RealtimeNotificationHandler extends StatefulWidget { const RealtimeNotificationHandler({ required this.child, required this.realtimeService, super.key, }); final Widget child; final RealtimeNotificationService realtimeService; @override State createState() => _RealtimeNotificationHandlerState(); } class _RealtimeNotificationHandlerState extends State { StreamSubscription? _friendRequestSub; StreamSubscription? _systemNotificationSub; StreamSubscription? _messageAlertSub; @override void initState() { super.initState(); _setupListeners(); } void _setupListeners() { // Écouter les demandes d'amitié _friendRequestSub = widget.realtimeService.friendRequestStream.listen((notification) { _showToast(notification.toDisplayMessage(), type: _getNotificationType(notification.type)); }); // Écouter les notifications système _systemNotificationSub = widget.realtimeService.systemNotificationStream.listen((notification) { _showSystemNotification(notification); }); // Écouter les alertes de messages _messageAlertSub = widget.realtimeService.messageAlertStream.listen((alert) { _showToast('Nouveau message de ${alert.senderName}', type: NotificationType.info); }); } /// Détermine le type de notification pour le style du toast. NotificationType _getNotificationType(String type) { switch (type) { case 'accepted': return NotificationType.success; case 'rejected': return NotificationType.warning; case 'received': default: return NotificationType.info; } } /// Affiche un toast (SnackBar) avec le message. void _showToast(String message, {NotificationType type = NotificationType.info}) { if (!mounted) return; final color = _getColorForType(type); final icon = _getIconForType(type); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ Icon(icon, color: Colors.white, size: 20), const SizedBox(width: 12), Expanded( child: Text( message, style: const TextStyle(color: Colors.white), ), ), ], ), backgroundColor: color, behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 4), action: SnackBarAction( label: 'OK', textColor: Colors.white, onPressed: () { ScaffoldMessenger.of(context).hideCurrentSnackBar(); }, ), ), ); } /// Affiche une notification système plus élaborée. void _showSystemNotification(SystemNotification notification) { if (!mounted) return; final color = _getColorForSystemNotificationType(notification.type); final icon = _getIconForSystemNotificationType(notification.type); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: Colors.white, size: 20), const SizedBox(width: 12), Expanded( child: Text( notification.title, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14, ), ), ), ], ), if (notification.message.isNotEmpty) ...[ const SizedBox(height: 4), Padding( padding: const EdgeInsets.only(left: 32), child: Text( notification.message, style: const TextStyle(color: Colors.white70, fontSize: 12), maxLines: 2, overflow: TextOverflow.ellipsis, ), ), ], ], ), backgroundColor: color, behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 5), action: SnackBarAction( label: 'OK', textColor: Colors.white, onPressed: () { ScaffoldMessenger.of(context).hideCurrentSnackBar(); }, ), ), ); } /// Retourne la couleur appropriée selon le type de notification. Color _getColorForType(NotificationType type) { switch (type) { case NotificationType.success: return Colors.green.shade600; case NotificationType.warning: return Colors.orange.shade600; case NotificationType.error: return Colors.red.shade600; case NotificationType.info: default: return Colors.blue.shade600; } } /// Retourne l'icône appropriée selon le type de notification. IconData _getIconForType(NotificationType type) { switch (type) { case NotificationType.success: return Icons.check_circle; case NotificationType.warning: return Icons.warning; case NotificationType.error: return Icons.error; case NotificationType.info: default: return Icons.info; } } /// Retourne la couleur appropriée selon le type de notification système. Color _getColorForSystemNotificationType(String type) { switch (type.toLowerCase()) { case 'event': return Colors.blue.shade600; case 'friend': return Colors.green.shade600; case 'reminder': return Colors.orange.shade600; default: return Colors.grey.shade700; } } /// Retourne l'icône appropriée selon le type de notification système. IconData _getIconForSystemNotificationType(String type) { switch (type.toLowerCase()) { case 'event': return Icons.event; case 'friend': return Icons.people; case 'reminder': return Icons.notifications; default: return Icons.info; } } @override void dispose() { _friendRequestSub?.cancel(); _systemNotificationSub?.cancel(); _messageAlertSub?.cancel(); super.dispose(); } @override Widget build(BuildContext context) => widget.child; } /// Enum pour les types de notifications toast. enum NotificationType { success, warning, error, info, }