Introduce a local mechanism for managing the app's badge count

This commit is contained in:
Stefan Ceriu
2026-09-08 19:05:44 +03:00
parent 7be93f8da8
commit 58628bd7c5
13 changed files with 164 additions and 6 deletions
+35 -5
View File
@@ -20,6 +20,9 @@ nonisolated class NotificationHandler {
private let notificationContentBuilder: NotificationContentBuilder
/// Whether this handler has already counted its notification towards the app icon badge.
private var hasCountedTowardsBadge = false
init(userSession: NSEUserSession,
settings: CommonSettingsProtocol,
contentHandler: @escaping (UNNotificationContent) -> Void,
@@ -42,9 +45,11 @@ nonisolated class NotificationHandler {
func processEvent(_ eventID: String, roomID: String) async {
MXLog.info("\(tag) Processing event: \(eventID) in room: \(roomID)")
// Copy over the unread information to the notification badge
notificationContent.badge = notificationContent.unreadCount as NSNumber?
MXLog.info("\(tag) New badge value: \(notificationContent.badge?.stringValue ?? "nil")")
if !settings.roomListNotificationCountEnabled {
// Copy over the unread information provided by the push payload to the notification badge.
notificationContent.badge = notificationContent.unreadCount as NSNumber?
MXLog.info("\(tag) New badge value: \(notificationContent.badge?.stringValue ?? "nil")")
}
guard let notificationItemProxy = await userSession.notificationItemProxy(roomID: roomID, eventID: eventID) else {
MXLog.error("\(tag) Failed retrieving notification item")
@@ -79,15 +84,37 @@ nonisolated class NotificationHandler {
// MARK: - Private
private func deliverNotification() {
MXLog.info("\(tag) Delivering notification")
if settings.roomListNotificationCountEnabled {
notificationContent.badge = NSNumber(value: incrementBadgeCount())
MXLog.info("\(tag) Delivering notification, new badge value: \(settings.lastKnownBadgeCount)")
} else {
MXLog.info("\(tag) Delivering notification")
}
contentHandler(notificationContent)
}
private func incrementBadgeCount() -> Int {
// `handleTimeExpiration` can deliver a notification this handler already delivered.
guard !hasCountedTowardsBadge else {
return settings.lastKnownBadgeCount
}
hasCountedTowardsBadge = true
settings.lastKnownBadgeCount += 1
return settings.lastKnownBadgeCount
}
private func discardNotification() {
MXLog.info("\(tag) Discarding notification")
let content = UNMutableNotificationContent()
content.badge = notificationContent.unreadCount as NSNumber?
if settings.roomListNotificationCountEnabled {
// Nothing new is shown to the user, so leave the badge where the app last put it.
content.badge = NSNumber(value: settings.lastKnownBadgeCount)
} else {
content.badge = notificationContent.unreadCount as NSNumber?
}
MXLog.info("\(tag) New badge value: \(content.badge?.stringValue ?? "nil")")
contentHandler(content)
@@ -122,6 +149,9 @@ nonisolated class NotificationHandler {
if let targetNotification = deliveredNotifications.first(where: { $0.request.content.eventID == redactedEventID }) {
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [targetNotification.request.identifier])
if settings.roomListNotificationCountEnabled {
settings.lastKnownBadgeCount = max(0, settings.lastKnownBadgeCount - 1)
}
}
return .processedShouldDiscard
@@ -258,7 +258,9 @@ actor NotificationServiceExtensionActor {
let content = UNMutableNotificationContent()
content.body = L10n.notificationReceivedWhileOfflineIos
content.badge = originalRequest.content.unreadCount as NSNumber?
if !settings.roomListNotificationCountEnabled {
content.badge = originalRequest.content.unreadCount as NSNumber?
}
content.sound = settings.notificationSound
let request = UNNotificationRequest(identifier: Self.receivedWhileOfflineNotificationID, content: content, trigger: nil)