feat(notifications): handle tap navigation to device alerts

Route FCM and local notification taps to the device alerts screen
when the user is already inside the legacy dashboard. Adds payload
parsing with command-based routing and richer debug logs.
This commit is contained in:
2026-04-17 09:42:07 +02:00
parent e7a4653c01
commit ecbb6d1e76

View File

@@ -3,6 +3,8 @@ import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:navigation/navigation.dart';
import 'package:sf_app_platform/navigation/app_router.dart';
/// Background message handler. MUST be a top-level function annotated with /// Background message handler. MUST be a top-level function annotated with
/// `@pragma('vm:entry-point')` so the Flutter engine can dispatch it from a /// `@pragma('vm:entry-point')` so the Flutter engine can dispatch it from a
@@ -15,9 +17,9 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
/// isolate. /// isolate.
@pragma('vm:entry-point') @pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async { Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
debugPrint( debugPrint('[FCM-bg] messageId: ${message.messageId}');
'[FCM-bg] message received: ${message.messageId} - ${message.notification?.title}', debugPrint('[FCM-bg] notification: title=${message.notification?.title}, body=${message.notification?.body}');
); debugPrint('[FCM-bg] data: ${message.data}');
} }
const String _localChannelId = 'sf_default_channel'; const String _localChannelId = 'sf_default_channel';
@@ -96,9 +98,9 @@ Future<void> _initLocalNotifications() async {
} }
void _onForegroundMessage(RemoteMessage message) { void _onForegroundMessage(RemoteMessage message) {
debugPrint( debugPrint('[FCM-fg] messageId: ${message.messageId}');
'[FCM-fg] message received: ${message.messageId} - ${message.notification?.title}', debugPrint('[FCM-fg] notification: title=${message.notification?.title}, body=${message.notification?.body}');
); debugPrint('[FCM-fg] data: ${message.data}');
final notification = message.notification; final notification = message.notification;
if (notification == null) return; if (notification == null) return;
@@ -128,15 +130,39 @@ void _onForegroundMessage(RemoteMessage message) {
} }
void _onMessageOpenedApp(RemoteMessage message) { void _onMessageOpenedApp(RemoteMessage message) {
debugPrint( debugPrint('[FCM-tap] messageId: ${message.messageId}');
'[FCM-tap] user tapped notification: ${message.messageId} - data: ${message.data}', debugPrint('[FCM-tap] notification: title=${message.notification?.title}, body=${message.notification?.body}');
); debugPrint('[FCM-tap] data: ${message.data}');
// TODO: handle deep linking based on message.data. _handleNotificationNavigation(message.data);
} }
void _onLocalNotificationTapped(NotificationResponse response) { void _onLocalNotificationTapped(NotificationResponse response) {
debugPrint( debugPrint('[LocalNotif-tap] id=${response.id}');
'[FCM-localtap] user tapped local notification: id=${response.id} payload=${response.payload}', debugPrint('[LocalNotif-tap] payload=${response.payload}');
); debugPrint('[LocalNotif-tap] actionId=${response.actionId}');
// TODO: handle deep linking. Payload contains JSON-encoded message.data.
final payload = response.payload;
if (payload == null || payload.isEmpty) return;
try {
final data = jsonDecode(payload) as Map<String, dynamic>;
_handleNotificationNavigation(data);
} catch (e) {
debugPrint('[LocalNotif-tap] failed to parse payload: $e');
}
}
void _handleNotificationNavigation(Map<String, dynamic> data) {
final currentLocation =
appRouter.routerDelegate.currentConfiguration.uri.path;
if (!currentLocation.startsWith(AppRoutes.legacyDashboard)) return;
final command = data['command'] as String?;
switch (command) {
case 'ALERT':
appRouter.go(AppRoutes.deviceAlertsNotifications);
default:
debugPrint('[Notification] unhandled command: $command');
}
} }