From b70bb956efcb9fea703e47e93595b0178dc8f1aa Mon Sep 17 00:00:00 2001 From: Mudit200408 Date: Thu, 28 May 2026 18:37:21 +0530 Subject: [PATCH 1/3] fix(notification): prevent duplicate notification cards and redundant alert triggers --- airsync-mac/Core/AppState.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/airsync-mac/Core/AppState.swift b/airsync-mac/Core/AppState.swift index 3d1b398e..c4c53ffa 100644 --- a/airsync-mac/Core/AppState.swift +++ b/airsync-mac/Core/AppState.swift @@ -1066,12 +1066,19 @@ class AppState: ObservableObject { func addNotification(_ notif: Notification) { DispatchQueue.main.async { + var contentChanged = true withAnimation { - self.notifications.insert(notif, at: 0) + if let idx = self.notifications.firstIndex(where: { $0.nid == notif.nid }) { + let old = self.notifications[idx] + contentChanged = (old.title != notif.title || old.body != notif.body || old.actions != notif.actions) + self.notifications[idx] = notif + } else { + self.notifications.insert(notif, at: 0) + } } - // Trigger native macOS notification if not silent + // Trigger native macOS notification if not silent and content actually changed/new // Default to alerting if priority is missing (backwards compatibility) - if notif.priority != "silent" { + if notif.priority != "silent" && contentChanged { var appIcon: NSImage? = nil if let iconPath = self.androidApps[notif.package]?.iconUrl { appIcon = NSImage(contentsOfFile: iconPath) From 8da609576bbba210db8f3683d1c43637b5b133a7 Mon Sep 17 00:00:00 2001 From: Mudit200408 Date: Thu, 28 May 2026 18:37:29 +0530 Subject: [PATCH 2/3] fix(notification): prevent false auto-dismissals during Focus mode and DND --- airsync-mac/Core/AppState.swift | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/airsync-mac/Core/AppState.swift b/airsync-mac/Core/AppState.swift index c4c53ffa..16841f0f 100644 --- a/airsync-mac/Core/AppState.swift +++ b/airsync-mac/Core/AppState.swift @@ -1211,17 +1211,22 @@ class AppState: ObservableObject { } func syncWithSystemNotifications() { - UNUserNotificationCenter.current().getDeliveredNotifications { systemNotifs in - let systemNIDs = Set(systemNotifs.map { $0.request.identifier }) + UNUserNotificationCenter.current().getNotificationSettings { settings in + guard settings.authorizationStatus == .authorized else { + return + } + UNUserNotificationCenter.current().getDeliveredNotifications { systemNotifs in + let systemNIDs = Set(systemNotifs.map { $0.request.identifier }) - DispatchQueue.main.async { - // Only sync notifications that were actually posted to system (non-silent) - let currentSystemNIDs = Set(self.notifications.filter { $0.priority != "silent" }.map { $0.nid }) - let removedNIDs = currentSystemNIDs.subtracting(systemNIDs) + DispatchQueue.main.async { + // Only sync notifications that were actually posted to system (non-silent) + let currentSystemNIDs = Set(self.notifications.filter { $0.priority != "silent" }.map { $0.nid }) + let removedNIDs = currentSystemNIDs.subtracting(systemNIDs) - for nid in removedNIDs { - print("[state] (notification) System notification \(nid) was dismissed manually.") - self.removeNotificationById(nid) + for nid in removedNIDs { + print("[state] (notification) System notification \(nid) was dismissed manually.") + self.removeNotificationById(nid) + } } } } From 6901b7be12cfad1bbb93fe4982b0bda0d6006958 Mon Sep 17 00:00:00 2001 From: Mudit200408 Date: Thu, 28 May 2026 18:37:42 +0530 Subject: [PATCH 3/3] fix(notification): make notification hiding local and remove invalid delegate method --- airsync-mac/Core/AppState.swift | 2 +- airsync-mac/Core/Util/NotificationDelegate.swift | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/airsync-mac/Core/AppState.swift b/airsync-mac/Core/AppState.swift index 16841f0f..7167a03c 100644 --- a/airsync-mac/Core/AppState.swift +++ b/airsync-mac/Core/AppState.swift @@ -951,7 +951,7 @@ class AppState: ObservableObject { withAnimation { self.notifications.removeAll { $0.id == notif.id } } - self.removeNotification(notif) + UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notif.nid]) } } diff --git a/airsync-mac/Core/Util/NotificationDelegate.swift b/airsync-mac/Core/Util/NotificationDelegate.swift index b2a51ccb..f26ab625 100644 --- a/airsync-mac/Core/Util/NotificationDelegate.swift +++ b/airsync-mac/Core/Util/NotificationDelegate.swift @@ -10,16 +10,6 @@ import UserNotifications @MainActor class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { - func userNotificationCenter(_ center: UNUserNotificationCenter, - didRemoveDeliveredNotifications identifiers: [String]) { - for nid in identifiers { - print("[notification-delegate] User dismissed system notification with nid: \(nid)") - DispatchQueue.main.async { - AppState.shared.removeNotificationById(nid) - } - } - } - func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {