import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:travel_mate/services/logger_service.dart'; class NotificationService { static final NotificationService _instance = NotificationService._internal(); factory NotificationService() => _instance; NotificationService._internal(); final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; final FlutterLocalNotificationsPlugin _localNotifications = FlutterLocalNotificationsPlugin(); bool _isInitialized = false; Future initialize() async { if (_isInitialized) return; // Request permissions await _requestPermissions(); // Initialize local notifications const androidSettings = AndroidInitializationSettings( '@mipmap/ic_launcher', ); const iosSettings = DarwinInitializationSettings(); const initSettings = InitializationSettings( android: androidSettings, iOS: iosSettings, ); await _localNotifications.initialize( initSettings, onDidReceiveNotificationResponse: (details) { // Handle notification tap LoggerService.info('Notification tapped: ${details.payload}'); }, ); // Handle foreground messages FirebaseMessaging.onMessage.listen(_handleForegroundMessage); _isInitialized = true; LoggerService.info('NotificationService initialized'); } Future _requestPermissions() async { NotificationSettings settings = await _firebaseMessaging.requestPermission( alert: true, badge: true, sound: true, ); LoggerService.info( 'User granted permission: ${settings.authorizationStatus}', ); } Future getFCMToken() async { try { if (Platform.isIOS) { String? apnsToken = await _firebaseMessaging.getAPNSToken(); int retries = 0; while (apnsToken == null && retries < 3) { LoggerService.info( 'Waiting for APNS token... (Attempt ${retries + 1}/3)', ); await Future.delayed(const Duration(seconds: 1)); apnsToken = await _firebaseMessaging.getAPNSToken(); retries++; } if (apnsToken == null) { LoggerService.error('APNS token not available after retries'); return null; } } final token = await _firebaseMessaging.getToken(); LoggerService.info('NotificationService - FCM Token: $token'); return token; } catch (e) { LoggerService.error('Error getting FCM token: $e'); return null; } } Future _handleForegroundMessage(RemoteMessage message) async { LoggerService.info('Got a message whilst in the foreground!'); LoggerService.info('Message data: ${message.data}'); if (message.notification != null) { LoggerService.info( 'Message also contained a notification: ${message.notification}', ); // Show local notification const androidDetails = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, ); const iosDetails = DarwinNotificationDetails(); const details = NotificationDetails( android: androidDetails, iOS: iosDetails, ); await _localNotifications.show( message.hashCode, message.notification?.title, message.notification?.body, details, ); } } }