Client: mirror branded notification sound to customer app

The customer app now uses the same halobestie_notif.ogg as the mitra
app (shipped in the previous commit). Channel ID unified across both
apps so backend FCM stops branching per recipient.

- client_app: same channel bump (chat_messages → halobestie_chat_v1)
  + RawResourceAndroidNotificationSound binding, both at channel-
  create time and per-notification details. .ogg copied to
  client_app/android/app/src/main/res/raw/halobestie_notif.ogg
  (same 32 KB asset, identical file).
- Backend: drop the per-recipientType channel ID branch; everyone
  targets halobestie_chat_v1 now.

Verified on emulator-5554 (customer): dumpsys shows the channel
bound to android.resource://com.mybestie/raw/halobestie_notif.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 20:05:05 +08:00
parent 9de6b8a78f
commit 1653482d54
3 changed files with 16 additions and 12 deletions

View File

@@ -21,14 +21,6 @@ export const sendPushNotification = async (recipientType, recipientId, { title,
if (!user?.fcm_token) return false 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 { try {
await admin.messaging().send({ await admin.messaging().send({
token: user.fcm_token, token: user.fcm_token,
@@ -41,7 +33,10 @@ export const sendPushNotification = async (recipientType, recipientId, { title,
}, },
android: { android: {
priority: 'high', 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: { apns: {
payload: { payload: {

View File

@@ -8,11 +8,17 @@ class NotificationService {
static final _localNotifications = FlutterLocalNotificationsPlugin(); static final _localNotifications = FlutterLocalNotificationsPlugin();
static GoRouter? _router; 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( static const _channel = AndroidNotificationChannel(
'chat_messages', 'halobestie_chat_v1',
'Chat Messages', 'Chat HaloBestie',
description: 'Notifications for incoming chat messages', description: 'Notifications for incoming chat messages and pairing requests',
importance: Importance.high, importance: Importance.high,
sound: RawResourceAndroidNotificationSound('halobestie_notif'),
); );
static Future<void> initialize(GoRouter router) async { static Future<void> initialize(GoRouter router) async {
@@ -60,6 +66,9 @@ class NotificationService {
channelDescription: _channel.description, channelDescription: _channel.description,
importance: Importance.high, importance: Importance.high,
priority: Priority.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( iOS: const DarwinNotificationDetails(
presentAlert: true, presentAlert: true,