Files
terrain_monitor_app/lib/services/notification_service.dart
2025-10-20 19:17:45 +02:00

187 lines
5.6 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'auth_service.dart';
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('Background message: ${message.messageId}');
}
class NotificationService {
static final NotificationService _instance = NotificationService._internal();
factory NotificationService() => _instance;
NotificationService._internal();
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
final FlutterLocalNotificationsPlugin _localNotifications =
FlutterLocalNotificationsPlugin();
bool _initialized = false;
// Stream per gestire i tap sulle notifiche
final StreamController<RemoteMessage> _messageStreamController =
StreamController<RemoteMessage>.broadcast();
Stream<RemoteMessage> get onMessageTap => _messageStreamController.stream;
Future<void> initialize() async {
if (_initialized) return;
try {
await _requestPermissions();
await _initializeLocalNotifications();
_configureHandlers();
await _getFcmToken();
_initialized = true;
print('NotificationService initialized');
} catch (e) {
print('Error initializing notifications: $e');
}
}
Future<void> _requestPermissions() async {
final settings = await _firebaseMessaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
print('Notification permission: ${settings.authorizationStatus}');
}
Future<void> _initializeLocalNotifications() async {
const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
const iosSettings = DarwinInitializationSettings();
await _localNotifications.initialize(
const InitializationSettings(android: androidSettings, iOS: iosSettings),
onDidReceiveNotificationResponse: _onNotificationTapped,
);
const channel = AndroidNotificationChannel(
'allarmi_channel',
'Allarmi',
description: 'Notifiche per allarmi del sistema di monitoraggio',
importance: Importance.high,
playSound: true,
enableVibration: true,
);
await _localNotifications
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
}
void _onNotificationTapped(NotificationResponse response) {
print('Notifica tappata: ${response.payload}');
if (response.payload != null && response.payload!.isNotEmpty) {
try {
final data = jsonDecode(response.payload!);
// Crea un RemoteMessage mock per compatibilità
final message = RemoteMessage(
data: data,
messageId: DateTime.now().toString(),
);
_messageStreamController.add(message);
} catch (e) {
print('Errore parsing payload: $e');
}
}
}
void _configureHandlers() {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessage.listen(_handleForegroundMessage);
// Handler quando app aperta da notifica (background/terminated)
FirebaseMessaging.onMessageOpenedApp.listen((message) {
print('Notifica aperta (background): ${message.messageId}');
_messageStreamController.add(message);
});
// Controlla se app avviata da notifica
_firebaseMessaging.getInitialMessage().then((message) {
if (message != null) {
print('App avviata da notifica: ${message.messageId}');
_messageStreamController.add(message);
}
});
}
Future<void> _getFcmToken() async {
try {
final token = await _firebaseMessaging.getToken();
if (token != null) {
print('FCM Token: $token');
await AuthService().saveFcmToken(token);
}
_firebaseMessaging.onTokenRefresh.listen((newToken) {
AuthService().saveFcmToken(newToken);
});
} catch (e) {
print('Error getting FCM token: $e');
}
}
Future<void> _handleForegroundMessage(RemoteMessage message) async {
print('Foreground message: ${message.messageId}');
final notification = message.notification;
if (notification != null) {
await _showLocalNotification(
title: notification.title ?? 'ASE Monitor',
body: notification.body ?? 'Nuovo allarme',
payload: jsonEncode(message.data),
);
}
}
Future<void> _showLocalNotification({
required String title,
required String body,
String? payload,
}) async {
const androidDetails = AndroidNotificationDetails(
'allarmi_channel',
'Allarmi',
channelDescription: 'Notifiche per allarmi del sistema di monitoraggio',
importance: Importance.high,
priority: Priority.high,
playSound: true,
enableVibration: true,
icon: '@mipmap/ic_launcher',
);
const iosDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
);
await _localNotifications.show(
DateTime.now().millisecondsSinceEpoch ~/ 1000,
title,
body,
const NotificationDetails(android: androidDetails, iOS: iosDetails),
payload: payload,
);
}
Future<String?> getFcmToken() async {
try {
return await _firebaseMessaging.getToken();
} catch (e) {
print('Errore ottenimento FCM token: $e');
return null;
}
}
void dispose() {
_messageStreamController.close();
}
}