diff --git a/ElementX/Sources/FlowCoordinators/ChatsTabFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/ChatsTabFlowCoordinator.swift index c8be799ec..9c819da62 100644 --- a/ElementX/Sources/FlowCoordinators/ChatsTabFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/ChatsTabFlowCoordinator.swift @@ -337,12 +337,6 @@ class ChatsTabFlowCoordinator: FlowCoordinatorProtocol { switch action { case .receivedDecryptionError(let info): processDecryptionError(info) - case .receivedSyncUpdate: - Task { - let roomSummaries = self.userSession.clientProxy.staticRoomSummaryProvider.roomListPublisher.value - await self.flowParameters.notificationManager.removeDeliveredNotificationsForFullyReadRooms(roomSummaries) - await self.flowParameters.notificationManager.updateAppBadgeCount() - } default: break } diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index e18b1ad46..e15dc861a 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -317,6 +317,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { .store(in: &cancellables) setupCallObservers() + setupUnreadNotificationsObserver() searchScreenCoordinator?.actionsPublisher .sink { [weak self] action in @@ -530,6 +531,22 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { navigationTabCoordinator.setOverlayPresentationMode(.minimized) } + private func setupUnreadNotificationsObserver() { + let roomListPublisher = userSession.clientProxy.staticRoomSummaryProvider.roomListPublisher + + Task { [weak self] in + for await roomSummaries in roomListPublisher.values { + guard let self else { return } + + let badgeCount = Int(userSession.clientProxy.totalUnreadNotifications) + + await flowParameters.notificationManager.removeDeliveredNotificationsForFullyReadRooms(roomSummaries) + await flowParameters.notificationManager.updateAppBadgeCount(badgeCount) + } + } + .store(in: &cancellables) + } + // MARK: - Native calls private func setupCallObservers() { diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index fa6da126c..d0b4a4cef 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -9039,11 +9039,25 @@ nonisolated class NotificationManagerMock: NotificationManagerProtocol, @uncheck var updateAppBadgeCountCalled: Bool { return updateAppBadgeCountCallsCount > 0 } - nonisolated(unsafe) var updateAppBadgeCountClosure: (() async -> Void)? + private let updateAppBadgeCountReceivedBadgeCountLock = NSLock() + private nonisolated(unsafe) var updateAppBadgeCountUnderlyingReceivedBadgeCount: Int? + var updateAppBadgeCountReceivedBadgeCount: Int? { + get { updateAppBadgeCountReceivedBadgeCountLock.withLock { updateAppBadgeCountUnderlyingReceivedBadgeCount } } + set { updateAppBadgeCountReceivedBadgeCountLock.withLock { updateAppBadgeCountUnderlyingReceivedBadgeCount = newValue } } + } + private let updateAppBadgeCountReceivedInvocationsLock = NSLock() + private nonisolated(unsafe) var updateAppBadgeCountUnderlyingReceivedInvocations: [Int] = [] + var updateAppBadgeCountReceivedInvocations: [Int] { + get { updateAppBadgeCountReceivedInvocationsLock.withLock { updateAppBadgeCountUnderlyingReceivedInvocations } } + set { updateAppBadgeCountReceivedInvocationsLock.withLock { updateAppBadgeCountUnderlyingReceivedInvocations = newValue } } + } + nonisolated(unsafe) var updateAppBadgeCountClosure: ((Int) async -> Void)? - @concurrent func updateAppBadgeCount() async { + @concurrent func updateAppBadgeCount(_ badgeCount: Int) async { updateAppBadgeCountCallsCountLock.withLock { updateAppBadgeCountUnderlyingCallsCount += 1 } - await updateAppBadgeCountClosure?() + updateAppBadgeCountReceivedBadgeCount = badgeCount + updateAppBadgeCountReceivedInvocationsLock.withLock { updateAppBadgeCountUnderlyingReceivedInvocations.append(badgeCount) } + await updateAppBadgeCountClosure?(badgeCount) } } nonisolated class NotificationSettingsProxyMock: NotificationSettingsProxyProtocol, @unchecked Sendable { diff --git a/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift b/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift index d9f939621..c1b3091b7 100644 --- a/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift +++ b/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift @@ -161,11 +161,9 @@ final class NotificationManager: NSObject, NotificationManagerProtocol { notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers) } - func updateAppBadgeCount() async { + func updateAppBadgeCount(_ badgeCount: Int) async { guard let userSession else { return } - let badgeCount = Int(userSession.clientProxy.totalUnreadNotifications) - appSettings.lastKnownBadgeCount = badgeCount MXLog.debug("Updating app badge count to \(badgeCount)") diff --git a/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift b/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift index 98d1f7d59..c62427c8d 100644 --- a/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift +++ b/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift @@ -37,5 +37,5 @@ protocol NotificationManagerProtocol: AnyObject { func removeDeliveredNotificationsForFullyReadRooms(_ rooms: [RoomSummary]) async - func updateAppBadgeCount() async + func updateAppBadgeCount(_ badgeCount: Int) async } diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index 1ff5b09c7..3650e3532 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -262,10 +262,8 @@ final class NotificationManagerTests { } @Test - func updatingAppBadgeCountUsesTheClientSideCount() async { - clientProxy.totalUnreadNotifications = 7 - - await notificationManager.updateAppBadgeCount() + func updatingAppBadgeCount() async { + await notificationManager.updateAppBadgeCount(7) #expect(notificationCenter.setBadgeCountReceivedNewBadgeCount == 7) #expect(appSettings.lastKnownBadgeCount == 7) @@ -275,7 +273,7 @@ final class NotificationManagerTests { func updatingAppBadgeCountWithoutASessionDoesNothing() async { notificationManager.setUserSession(nil) - await notificationManager.updateAppBadgeCount() + await notificationManager.updateAppBadgeCount(7) #expect(!notificationCenter.setBadgeCountCalled) }