import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter/foundation.dart'; /// Service de gestion des notifications chat /// /// Gère l'envoi et la réception des notifications pour le module chat class ChatNotificationService { static final ChatNotificationService _instance = ChatNotificationService._internal(); factory ChatNotificationService() => _instance; ChatNotificationService._internal(); final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; final FlutterLocalNotificationsPlugin _localNotifications = FlutterLocalNotificationsPlugin(); // Callback pour les actions sur les notifications Function(String messageId)? onMessageTap; Function(Map)? onBackgroundMessage; /// Initialise le service de notifications Future initialize() async { // Demander les permissions await _requestPermissions(); // Initialiser les notifications locales await _initializeLocalNotifications(); // Configurer les handlers de messages _configureFirebaseHandlers(); // Obtenir le token du device await _initializeDeviceToken(); } /// Demande les permissions pour les notifications Future _requestPermissions() async { NotificationSettings settings = await _firebaseMessaging.requestPermission( alert: true, badge: true, sound: true, provisional: false, ); return settings.authorizationStatus == AuthorizationStatus.authorized; } /// Initialise les notifications locales Future _initializeLocalNotifications() async { const AndroidInitializationSettings androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); final DarwinInitializationSettings iosSettings = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true, onDidReceiveLocalNotification: _onDidReceiveLocalNotification, ); final InitializationSettings initSettings = InitializationSettings( android: androidSettings, iOS: iosSettings, ); await _localNotifications.initialize( initSettings, onDidReceiveNotificationResponse: _onNotificationTap, ); } /// Configure les handlers Firebase void _configureFirebaseHandlers() { // Message reçu quand l'app est au premier plan FirebaseMessaging.onMessage.listen(_onForegroundMessage); // Message reçu quand l'app est en arrière-plan FirebaseMessaging.onMessageOpenedApp.listen(_onBackgroundMessageOpened); // Handler pour les messages en arrière-plan terminé FirebaseMessaging.onBackgroundMessage(_firebaseBackgroundHandler); } /// Handler pour les messages reçus au premier plan Future _onForegroundMessage(RemoteMessage message) async { if (message.notification != null) { // Afficher une notification locale await _showLocalNotification( title: message.notification!.title ?? 'Nouveau message', body: message.notification!.body ?? '', payload: message.data['messageId'] ?? '', ); } } /// Handler pour les messages ouverts depuis l'arrière-plan void _onBackgroundMessageOpened(RemoteMessage message) { final messageId = message.data['messageId']; if (messageId != null) { onMessageTap?.call(messageId); } } /// Affiche une notification locale Future _showLocalNotification({ required String title, required String body, required String payload, }) async { const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'chat_messages', 'Messages de chat', channelDescription: 'Notifications pour les nouveaux messages de chat', importance: Importance.high, priority: Priority.high, icon: '@mipmap/ic_launcher', ); const DarwinNotificationDetails iosDetails = DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, ); const NotificationDetails notificationDetails = NotificationDetails( android: androidDetails, iOS: iosDetails, ); await _localNotifications.show( DateTime.now().microsecondsSinceEpoch, title, body, notificationDetails, payload: payload, ); } /// Handler pour le clic sur une notification void _onNotificationTap(NotificationResponse response) { final payload = response.payload; if (payload != null) { onMessageTap?.call(payload); } } /// Handler pour les notifications iOS reçues au premier plan void _onDidReceiveLocalNotification(int id, String? title, String? body, String? payload) { // Traitement spécifique iOS si nécessaire } /// Obtient et stocke le token du device Future _initializeDeviceToken() async { String? token = await _firebaseMessaging.getToken(); if (token != null) { // Envoyer le token au serveur pour stocker await _sendTokenToServer(token); } // Écouter les changements de token _firebaseMessaging.onTokenRefresh.listen(_sendTokenToServer); return token; } /// Envoie le token FCM au serveur Future _sendTokenToServer(String token) async { try { // Appel API pour enregistrer le token // await chatApiService.registerDeviceToken(token); debugPrint('Device token enregistré : $token'); } catch (e) { debugPrint('Erreur lors de l\'enregistrement du token : $e'); } } /// S'abonner aux notifications pour une conversation Future subscribeToConversation(String conversationId) async { await _firebaseMessaging.subscribeToTopic('chat_$conversationId'); } /// Se désabonner des notifications pour une conversation Future unsubscribeFromConversation(String conversationId) async { await _firebaseMessaging.unsubscribeFromTopic('chat_$conversationId'); } /// Désactive temporairement les notifications Future pauseNotifications() async { await _firebaseMessaging.setAutoInitEnabled(false); } /// Réactive les notifications Future resumeNotifications() async { await _firebaseMessaging.setAutoInitEnabled(true); } } /// Handler pour les messages en arrière-plan @pragma('vm:entry-point') Future _firebaseBackgroundHandler(RemoteMessage message) async { // Traitement des messages en arrière-plan debugPrint('Message reçu en arrière-plan : ${message.messageId}'); }