diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index 9866be33..ea860ae0 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -253,7 +253,11 @@ class FirebaseNotificationManger { if (Platform.isAndroid) { if (message.data["notificationType"] != 'NurseConfirmArrive') { NotificationManger.showNotification( - title: message.notification?.title ?? "", subtext: message.notification?.body ?? "", hashcode: int.tryParse("1234" ?? "") ?? 1, payload: json.encode(message.data), context: context); + title: message.notification?.title ?? "", + subtext: message.notification?.body ?? "", + hashcode: DateTime.now().millisecondsSinceEpoch.hashCode, + payload: json.encode(message.data), + context: context); } } return; diff --git a/lib/controllers/notification/notification_manger.dart b/lib/controllers/notification/notification_manger.dart index ab1df81a..5e85c450 100644 --- a/lib/controllers/notification/notification_manger.dart +++ b/lib/controllers/notification/notification_manger.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -43,46 +44,71 @@ class NotificationManger { await localNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed); } // push new notification - static const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails( - 'com.hmg.atoms', - 'ATOMS', - channelDescription: 'Push notification service for ATOMS', - importance: Importance.max, - priority: Priority.max, - icon: "@drawable/ic_stat_name", - playSound: true, - channelShowBadge: true, - visibility: NotificationVisibility.public, - enableVibration: true, - groupKey: 'com.hmg.atoms', - ); - - static const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails( - categoryIdentifier: "atoms", - ); + static AndroidNotificationDetails androidNotificationDetails(String? groupId, String? channelId) => AndroidNotificationDetails( + channelId ?? 'com.hmg.atoms', + 'ATOMS', + channelDescription: 'Push notification service for ATOMS', + importance: Importance.max, + priority: Priority.max, + icon: "@drawable/ic_stat_name", + playSound: true, + channelShowBadge: true, + visibility: NotificationVisibility.public, + enableVibration: true, + groupKey: groupId ?? 'com.hmg.atoms', + ); + + static DarwinNotificationDetails iosNotificationDetails(String? threadId) => DarwinNotificationDetails(categoryIdentifier: "atoms", threadIdentifier: threadId); static Future showNotification({required BuildContext context, required String title, required String subtext, required int hashcode, String? payload}) async { - // const AndroidNotificationDetails androidChannel = AndroidNotificationDetails( - // 'com.hmg.atoms', - // 'ATOMS', - // channelDescription: 'Push notification service for ATOMS', - // importance: Importance.max, - // priority: Priority.max, - // icon: "@drawable/ic_stat_name", - // playSound: true, - // channelShowBadge: true, - // visibility: NotificationVisibility.public, - // enableVibration: true, - // groupKey: 'com.hmg.atoms', - // ); - - // const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails( - // categoryIdentifier: "atoms", - // ); - - const NotificationDetails platformChannel = NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails); + var dataPayload = json.decode(payload ?? "{}"); + String? groupId = dataPayload["group_id"]; + NotificationDetails platformChannel = NotificationDetails(android: androidNotificationDetails(groupId, groupId), iOS: iosNotificationDetails(groupId), macOS: iosNotificationDetails(groupId)); await localNotificationsPlugin.show(hashcode, title, subtext, platformChannel, payload: payload); + + // If there's a group_id, also show/update the summary notification + if (groupId != null && Platform.isAndroid) { + await _showGroupSummary(groupId); + } + } + + static final Map _groupCounts = {}; + + static Future _showGroupSummary(String groupId) async { + // Increment count for this group + _groupCounts[groupId] = (_groupCounts[groupId] ?? 0) + 1; + final count = _groupCounts[groupId]!; + + // Only show summary if we have 2+ notifications + if (count < 2) return; + + final AndroidNotificationDetails summaryDetails = AndroidNotificationDetails( + 'com.hmg.atoms', + 'ATOMS', + channelDescription: 'Push notification service for ATOMS', + importance: Importance.max, + priority: Priority.max, + icon: "@drawable/ic_stat_name", + groupKey: groupId, + setAsGroupSummary: true, + // THIS IS THE KEY + styleInformation: InboxStyleInformation( + [], + contentTitle: 'ATOMS', + summaryText: 'You have $count new notifications', + ), + ); + + // Use group_id's hashCode as the summary notification ID to ensure uniqueness + final int summaryId = groupId.hashCode; + + await localNotificationsPlugin.show( + summaryId, + 'ATOMS', + '$count new notifications', + NotificationDetails(android: summaryDetails), + ); } static Future scheduleNotification({int? id, String? title, String? body, String? payLoad, required DateTime scheduledNotificationDateTime}) async { @@ -95,7 +121,7 @@ class NotificationManger { scheduledNotificationDateTime, tz.local, ), - const NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails), + NotificationDetails(android: androidNotificationDetails(null, null), iOS: iosNotificationDetails(null), macOS: iosNotificationDetails(null)), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime); } @@ -103,4 +129,34 @@ class NotificationManger { static Future cancelNotificationById(int notificationId) async { await localNotificationsPlugin.cancel(notificationId); } + + /// Show group summary notification (for background isolate) + static Future _showGroupSummaryBackground(String groupId, FlutterLocalNotificationsPlugin plugin) async { + final AndroidNotificationDetails summaryDetails = AndroidNotificationDetails( + 'com.hmg.atoms', + 'ATOMS', + channelDescription: 'Push notification service for ATOMS', + importance: Importance.max, + priority: Priority.max, + icon: "@drawable/ic_stat_name", + groupKey: groupId, + setAsGroupSummary: true, + autoCancel: true, + onlyAlertOnce: true, + styleInformation: InboxStyleInformation( + [], + contentTitle: 'ATOMS', + summaryText: 'New notifications', + ), + ); + + final int summaryId = groupId.hashCode; + + await plugin.show( + summaryId, + 'ATOMS', + 'New notifications', + NotificationDetails(android: summaryDetails), + ); + } }