From b1eb9bf466154a12e6659dc1ea2126c3973957da Mon Sep 17 00:00:00 2001 From: Excelsior <33706074+epicexcelsior@users.noreply.github.com> Date: Mon, 18 May 2026 02:53:34 -0800 Subject: [PATCH] fix(notifications): collapse per-peer message notifs instead of stacking (#78) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Background-delivered messages scheduled a fresh notification request per event, so iOS stacked one banner per message in the tray (same symptom as F9 — "push notifications spammed instead of updated"). Android was saved only by the channel-level group fallback. Pass a per-peer identifier (`anonmesh-msg-`) on scheduleNotificationAsync. On iOS this reuses the same UNNotificationRequest slot so a follow-up message replaces the unread banner instead of stacking; on Android same-identifier reuse updates the existing notification in place. Mirrors the single-id pattern already used by usePeerCountNotification. No new permissions or native config. --- mobile_app/hooks/useMessageNotifications.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mobile_app/hooks/useMessageNotifications.ts b/mobile_app/hooks/useMessageNotifications.ts index 9b04de63..bedc6e09 100644 --- a/mobile_app/hooks/useMessageNotifications.ts +++ b/mobile_app/hooks/useMessageNotifications.ts @@ -82,7 +82,12 @@ export function useMessageNotifications( if (appStateRef.current === 'active') { onInApp(payload); } else { + // Per-peer identifier replaces any prior unread notification from the + // same sender instead of stacking. Matches usePeerCountNotification's + // single-id pattern. On iOS this maps to UNNotificationRequest reuse; + // on Android the channel already groups under 'messages'. Notifications.scheduleNotificationAsync({ + identifier: `anonmesh-msg-${srcHash}`, content: { title: sender, body: 'new message', sound: true }, trigger: null, }).catch(() => {});