diff --git a/backend/src/services/notification.service.js b/backend/src/services/notification.service.js index c055961..f59b5b3 100644 --- a/backend/src/services/notification.service.js +++ b/backend/src/services/notification.service.js @@ -21,14 +21,6 @@ export const sendPushNotification = async (recipientType, recipientId, { title, if (!user?.fcm_token) return false - // Mitra app ships a branded notification sound on its own channel - // (`halobestie_chat_v1`, declared in mitra_app/lib/core/notifications/ - // notification_service.dart). Customer app keeps the legacy - // `chat_messages` channel until/unless we ship a customer sound too. - const androidChannelId = recipientType === UserType.MITRA - ? 'halobestie_chat_v1' - : 'chat_messages' - try { await admin.messaging().send({ token: user.fcm_token, @@ -41,7 +33,10 @@ export const sendPushNotification = async (recipientType, recipientId, { title, }, android: { priority: 'high', - notification: { channelId: androidChannelId }, + // Both apps register the same channel ID with the branded + // notification sound (halobestie_notif.ogg in res/raw). See each + // app's lib/core/notifications/notification_service.dart. + notification: { channelId: 'halobestie_chat_v1' }, }, apns: { payload: { diff --git a/client_app/android/app/src/main/res/raw/halobestie_notif.ogg b/client_app/android/app/src/main/res/raw/halobestie_notif.ogg new file mode 100644 index 0000000..c36af26 Binary files /dev/null and b/client_app/android/app/src/main/res/raw/halobestie_notif.ogg differ diff --git a/client_app/lib/core/notifications/notification_service.dart b/client_app/lib/core/notifications/notification_service.dart index a0516b8..ca09662 100644 --- a/client_app/lib/core/notifications/notification_service.dart +++ b/client_app/lib/core/notifications/notification_service.dart @@ -8,11 +8,17 @@ class NotificationService { static final _localNotifications = FlutterLocalNotificationsPlugin(); static GoRouter? _router; + // Channel ID bumped (`chat_messages` → `halobestie_chat_v1`) when the + // branded notification sound was introduced. Android binds sound to a + // channel at create time on API 26+, so an existing channel can't pick + // up a new sound — a fresh ID is the only way. Backend FCM payloads + // target the same ID — see backend/src/services/notification.service.js. static const _channel = AndroidNotificationChannel( - 'chat_messages', - 'Chat Messages', - description: 'Notifications for incoming chat messages', + 'halobestie_chat_v1', + 'Chat HaloBestie', + description: 'Notifications for incoming chat messages and pairing requests', importance: Importance.high, + sound: RawResourceAndroidNotificationSound('halobestie_notif'), ); static Future initialize(GoRouter router) async { @@ -60,6 +66,9 @@ class NotificationService { channelDescription: _channel.description, importance: Importance.high, priority: Priority.high, + // API 26+ ignores this in favor of the channel's sound; included + // for the API 24/25 path where channels don't exist yet. + sound: const RawResourceAndroidNotificationSound('halobestie_notif'), ), iOS: const DarwinNotificationDetails( presentAlert: true,