From 3ab7b1b1c7154b1832d7e2689e8e1c61139f9846 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Thu, 31 Aug 2023 13:15:38 +0200 Subject: [PATCH] Display the notification mode for each room in the the room list (#1595) Co-authored-by: Stefan Ceriu --- .../en.lproj/Localizable.strings | 2 + .../RoomFlowCoordinator.swift | 34 ++++++------- .../UserSessionFlowCoordinator.swift | 18 +++---- ElementX/Sources/Generated/Strings.swift | 4 ++ .../Screens/HomeScreen/HomeScreenModels.swift | 8 +++ .../HomeScreen/HomeScreenViewModel.swift | 5 +- .../HomeScreen/View/HomeScreenRoomCell.swift | 49 ++++++++++++++----- .../View/InvitesScreenCell.swift | 2 + .../View/DeveloperOptionsScreen.swift | 1 + .../Sources/Services/Client/ClientProxy.swift | 14 +++--- .../Services/Client/ClientProxyProtocol.swift | 4 +- .../Services/Client/MockClientProxy.swift | 11 +---- .../NotificationSettingsProxy.swift | 2 +- .../RoomSummary/MockRoomSummaryProvider.swift | 5 ++ .../Room/RoomSummary/RoomSummaryDetails.swift | 1 + .../RoomSummary/RoomSummaryProvider.swift | 47 ++++++++++++++++++ UnitTests/Sources/LoggingTests.swift | 1 + 17 files changed, 145 insertions(+), 63 deletions(-) diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index 1d1005717..00d90deb7 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -1,5 +1,7 @@ "Notification" = "Notification"; "a11y_hide_password" = "Hide password"; +"a11y_notifications_mentions_only" = "Mentions only"; +"a11y_notifications_muted" = "Muted"; "a11y_send_files" = "Send files"; "a11y_show_password" = "Show password"; "a11y_user_menu" = "User menu"; diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index cc74ea2b4..dbf87b58d 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -231,7 +231,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { break case (.roomDetails, .presentNotificationSettingsScreen, .notificationSettingsScreen): - asyncPresentNotificationSettingsScreen(animated: animated) + presentNotificationSettingsScreen(animated: animated) case (.notificationSettingsScreen, .dismissNotificationSettingsScreen, .roomDetails): break @@ -397,13 +397,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { return } - let params = await RoomDetailsScreenCoordinatorParameters(accountUserID: userSession.userID, - navigationStackCoordinator: navigationStackCoordinator, - roomProxy: roomProxy, - mediaProvider: userSession.mediaProvider, - userDiscoveryService: UserDiscoveryService(clientProxy: userSession.clientProxy), - userIndicatorController: userIndicatorController, - notificationSettings: userSession.clientProxy.notificationSettings()) + let params = RoomDetailsScreenCoordinatorParameters(accountUserID: userSession.userID, + navigationStackCoordinator: navigationStackCoordinator, + roomProxy: roomProxy, + mediaProvider: userSession.mediaProvider, + userDiscoveryService: UserDiscoveryService(clientProxy: userSession.clientProxy), + userIndicatorController: userIndicatorController, + notificationSettings: userSession.clientProxy.notificationSettings) let coordinator = RoomDetailsScreenCoordinator(parameters: params) coordinator.actions.sink { [weak self] action in switch action { @@ -691,19 +691,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { stateMachine.tryEvent(.presentRoom(roomID: roomID), userInfo: EventUserInfo(animated: true, destinationRoomProxy: targetRoomProxy)) } - private func asyncPresentNotificationSettingsScreen(animated: Bool) { - Task { - await presentNotificationSettingsScreen(animated: animated) - } - } - - private func presentNotificationSettingsScreen(animated: Bool) async { + private func presentNotificationSettingsScreen(animated: Bool) { let navigationCoordinator = NavigationStackCoordinator() - let parameters = await NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationCoordinator, - userSession: userSession, - userNotificationCenter: UNUserNotificationCenter.current(), - notificationSettings: userSession.clientProxy.notificationSettings(), - isModallyPresented: true) + let parameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationCoordinator, + userSession: userSession, + userNotificationCenter: UNUserNotificationCenter.current(), + notificationSettings: userSession.clientProxy.notificationSettings, + isModallyPresented: true) let coordinator = NotificationSettingsScreenCoordinator(parameters: parameters) coordinator.actions.sink { [weak self] action in switch action { diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index 9cdb03867..a1f073ade 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -297,22 +297,16 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { // MARK: Settings private func presentSettingsScreen(animated: Bool) { - Task { - await asyncPresentSettingsScreen(animated: animated) - } - } - - private func asyncPresentSettingsScreen(animated: Bool) async { let settingsNavigationStackCoordinator = NavigationStackCoordinator() let userIndicatorController = UserIndicatorController(rootCoordinator: settingsNavigationStackCoordinator) - let parameters = await SettingsScreenCoordinatorParameters(navigationStackCoordinator: settingsNavigationStackCoordinator, - userIndicatorController: userIndicatorController, - userSession: userSession, - bugReportService: bugReportService, - notificationSettings: userSession.clientProxy.notificationSettings(), - appSettings: appSettings) + let parameters = SettingsScreenCoordinatorParameters(navigationStackCoordinator: settingsNavigationStackCoordinator, + userIndicatorController: userIndicatorController, + userSession: userSession, + bugReportService: bugReportService, + notificationSettings: userSession.clientProxy.notificationSettings, + appSettings: appSettings) let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters) settingsScreenCoordinator.callback = { [weak self] action in guard let self else { return } diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index c519a6893..ad58aec2f 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -12,6 +12,10 @@ import Foundation public enum L10n { /// Hide password public static var a11yHidePassword: String { return L10n.tr("Localizable", "a11y_hide_password") } + /// Mentions only + public static var a11yNotificationsMentionsOnly: String { return L10n.tr("Localizable", "a11y_notifications_mentions_only") } + /// Muted + public static var a11yNotificationsMuted: String { return L10n.tr("Localizable", "a11y_notifications_muted") } /// Send files public static var a11ySendFiles: String { return L10n.tr("Localizable", "a11y_send_files") } /// Show password diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift index 5bd92e125..ebca8e5ca 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift @@ -139,6 +139,14 @@ struct HomeScreenRoom: Identifiable, Equatable { var avatarURL: URL? + var notificationMode: RoomNotificationModeProxy? + + var hasDecoration: Bool { + // notification setting is displayed only for .mentionsAndKeywords and .mute + let showNotificationSettings = notificationMode != nil + return hasUnreads || showNotificationSettings + } + var isPlaceholder = false static func placeholder() -> HomeScreenRoom { diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift index 04f9712bc..c2c5d2c5b 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift @@ -266,13 +266,16 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol private func buildRoom(with details: RoomSummaryDetails, invalidated: Bool) -> HomeScreenRoom { let identifier = invalidated ? "invalidated-" + details.id : details.id + let notificationMode = details.notificationMode == .allMessages || appSettings.notificationSettingsEnabled == false ? nil : details.notificationMode + return HomeScreenRoom(id: identifier, roomId: details.id, name: details.name, hasUnreads: details.unreadNotificationCount > 0, timestamp: details.lastMessageFormattedTimestamp, lastMessage: .init(attributedString: details.lastMessage, isLoading: false), - avatarURL: details.avatarURL) + avatarURL: details.avatarURL, + notificationMode: notificationMode) } private func updateVisibleRange(_ range: Range) { diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift index 864be144a..8d442860c 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift @@ -15,6 +15,7 @@ // import Combine +import Compound import SwiftUI struct HomeScreenRoomCell: View { @@ -115,17 +116,42 @@ struct HomeScreenRoomCell: View { Spacer() - if room.hasUnreads { - Circle() - .frame(width: 12, height: 12) - .foregroundColor(.compound.iconAccentTertiary) - .padding(.leading, 12) - } else { - // Force extra padding between last message text and the right border of the screen if there is no unread dot - Circle() - .frame(width: 12, height: 12) - .hidden() + HStack(spacing: 8) { + if let notificationMode = room.notificationMode { + notificationModeIcon + .foregroundColor(room.hasUnreads ? .compound.iconAccentTertiary : .compound.iconQuaternary) + } + + if room.hasUnreads { + Circle() + .frame(width: 12, height: 12) + .foregroundColor(.compound.iconAccentTertiary) + } + + if !room.hasDecoration { + // Force extra padding between last message text and the right border of the screen if there is no unread dot + Circle() + .frame(width: 12, height: 12) + .hidden() + } } + .padding(.leading, room.hasDecoration ? 12 : 0) + } + } + + @ViewBuilder + var notificationModeIcon: some View { + switch room.notificationMode { + case .none, .allMessages: + EmptyView() + case .mentionsAndKeywordsOnly: + CompoundIcon(\.mention) + .font(.system(size: 15)) + .accessibilityLabel(L10n.a11yNotificationsMentionsOnly) + case .mute: + CompoundIcon(\.notificationsSolidOff) + .font(.system(size: 15)) + .accessibilityLabel(L10n.a11yNotificationsMuted) } } @@ -191,7 +217,8 @@ struct HomeScreenRoomCell_Previews: PreviewProvider { hasUnreads: details.unreadNotificationCount > 0, timestamp: Date.now.formattedMinimal(), lastMessage: .init(attributedString: details.lastMessage, - isLoading: false)) + isLoading: false), + notificationMode: details.notificationMode) } } diff --git a/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift b/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift index 19c8eac6e..ebbd9538f 100644 --- a/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift +++ b/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift @@ -189,6 +189,7 @@ private extension InvitesScreenRoomDetails { lastMessage: nil, lastMessageFormattedTimestamp: nil, unreadNotificationCount: 0, + notificationMode: nil, canonicalAlias: "#footest:somewhere.org", inviter: inviter) return .init(roomDetails: dmRoom, isUnread: false) @@ -207,6 +208,7 @@ private extension InvitesScreenRoomDetails { lastMessage: nil, lastMessageFormattedTimestamp: nil, unreadNotificationCount: 0, + notificationMode: nil, canonicalAlias: alias, inviter: inviter) return .init(roomDetails: dmRoom, isUnread: isUnread) diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index d9556bfb7..0cac025cc 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -50,6 +50,7 @@ struct DeveloperOptionsScreen: View { Section("Notifications") { Toggle(isOn: $context.notificationSettingsEnabled) { Text("Show notification settings") + Text("Requires app reboot") } } diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index 61f2f8759..fe8c36e14 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -36,6 +36,8 @@ class ClientProxy: ClientProxyProtocol { var roomSummaryProvider: RoomSummaryProviderProtocol? var inviteSummaryProvider: RoomSummaryProviderProtocol? + + var notificationSettings: NotificationSettingsProxyProtocol private let roomListRecencyOrderingAllowedEventTypes = ["m.room.message", "m.room.encrypted", "m.sticker"] @@ -66,6 +68,9 @@ class ClientProxy: ClientProxyProtocol { clientQueue = .init(label: "ClientProxyQueue", attributes: .concurrent) mediaLoader = MediaLoader(client: client, clientQueue: clientQueue) + + notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings(), + backgroundTaskService: backgroundTaskService) client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in self?.callbacks.send(.receivedAuthError(isSoftLogout: isSoftLogout)) @@ -348,13 +353,6 @@ class ClientProxy: ClientProxyProtocol { } } - func notificationSettings() async -> NotificationSettingsProxyProtocol { - await Task.dispatch(on: clientQueue) { - NotificationSettingsProxy(notificationSettings: self.client.getNotificationSettings(), - backgroundTaskService: self.backgroundTaskService) - } - } - // MARK: Private private func restartSync(delay: Duration = .zero) { @@ -405,12 +403,14 @@ class ClientProxy: ClientProxyProtocol { eventStringBuilder: eventStringBuilder, name: "AllRooms", appSettings: appSettings, + notificationSettings: notificationSettings, backgroundTaskService: backgroundTaskService) try await roomSummaryProvider?.setRoomList(roomListService.allRooms()) inviteSummaryProvider = RoomSummaryProvider(roomListService: roomListService, eventStringBuilder: eventStringBuilder, name: "Invites", appSettings: appSettings, + notificationSettings: notificationSettings, backgroundTaskService: backgroundTaskService) self.syncService = syncService diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index 6d74784f6..c3a9dd167 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -83,6 +83,8 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol { var inviteSummaryProvider: RoomSummaryProviderProtocol? { get } + var notificationSettings: NotificationSettingsProxyProtocol { get } + func startSync() func stopSync() @@ -114,6 +116,4 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol { func searchUsers(searchTerm: String, limit: UInt) async -> Result func profile(for userID: String) async -> Result - - func notificationSettings() async -> NotificationSettingsProxyProtocol } diff --git a/ElementX/Sources/Services/Client/MockClientProxy.swift b/ElementX/Sources/Services/Client/MockClientProxy.swift index 8795434f8..b78a0031a 100644 --- a/ElementX/Sources/Services/Client/MockClientProxy.swift +++ b/ElementX/Sources/Services/Client/MockClientProxy.swift @@ -32,6 +32,8 @@ class MockClientProxy: ClientProxyProtocol { var inviteSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider() var avatarURLPublisher: AnyPublisher { Empty().eraseToAnyPublisher() } + + var notificationSettings: NotificationSettingsProxyProtocol = NotificationSettingsProxyMock(with: .init()) init(userID: String, deviceID: String? = nil, accountURL: URL? = nil, roomSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider()) { self.userID = userID @@ -141,13 +143,4 @@ class MockClientProxy: ClientProxyProtocol { getProfileCalled = true return getProfileResult } - - var notificationSettingsResult: NotificationSettingsProxyProtocol? - func notificationSettings() -> NotificationSettingsProxyProtocol { - if let notificationSettingsResult { - return notificationSettingsResult - } else { - return NotificationSettingsProxyMock(with: .init()) - } - } } diff --git a/ElementX/Sources/Services/NotificationSettings/NotificationSettingsProxy.swift b/ElementX/Sources/Services/NotificationSettings/NotificationSettingsProxy.swift index 149c42c4d..ff511c71f 100644 --- a/ElementX/Sources/Services/NotificationSettings/NotificationSettingsProxy.swift +++ b/ElementX/Sources/Services/NotificationSettings/NotificationSettingsProxy.swift @@ -37,7 +37,7 @@ private final class WeakNotificationSettingsProxy: NotificationSettingsDelegate final class NotificationSettingsProxy: NotificationSettingsProxyProtocol { private(set) var notificationSettings: MatrixRustSDK.NotificationSettingsProtocol private let backgroundTaskService: BackgroundTaskServiceProtocol? - + let callbacks = PassthroughSubject() init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol, backgroundTaskService: BackgroundTaskServiceProtocol?) { diff --git a/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift index ba974ec69..495d45798 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift @@ -57,6 +57,7 @@ extension Array where Element == RoomSummary { lastMessage: AttributedString("Prosciutto beef ribs pancetta filet mignon kevin hamburger, chuck ham venison picanha. Beef ribs chislic turkey biltong tenderloin."), lastMessageFormattedTimestamp: "Now", unreadNotificationCount: 4, + notificationMode: .allMessages, canonicalAlias: nil, inviter: RoomMemberProxyMock.mockCharlie)), .filled(details: RoomSummaryDetails(id: "2", @@ -66,6 +67,7 @@ extension Array where Element == RoomSummary { lastMessage: nil, lastMessageFormattedTimestamp: nil, unreadNotificationCount: 1, + notificationMode: .mentionsAndKeywordsOnly, canonicalAlias: nil, inviter: RoomMemberProxyMock.mockCharlie)), .filled(details: RoomSummaryDetails(id: "3", @@ -75,6 +77,7 @@ extension Array where Element == RoomSummary { lastMessage: try? AttributedString(markdown: "**@mock:client.com**: T-bone beef ribs bacon"), lastMessageFormattedTimestamp: "Later", unreadNotificationCount: 0, + notificationMode: .mute, canonicalAlias: nil, inviter: RoomMemberProxyMock.mockCharlie)), .empty @@ -87,6 +90,7 @@ extension Array where Element == RoomSummary { lastMessage: nil, lastMessageFormattedTimestamp: nil, unreadNotificationCount: 0, + notificationMode: nil, canonicalAlias: "#footest:somewhere.org", inviter: RoomMemberProxyMock.mockCharlie)), .filled(details: RoomSummaryDetails(id: "someAwesomeRoomId2", @@ -96,6 +100,7 @@ extension Array where Element == RoomSummary { lastMessage: nil, lastMessageFormattedTimestamp: nil, unreadNotificationCount: 0, + notificationMode: nil, canonicalAlias: nil, inviter: RoomMemberProxyMock.mockCharlie)) ] diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift index 08173c384..a5b224366 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift @@ -25,6 +25,7 @@ struct RoomSummaryDetails { let lastMessage: AttributedString? let lastMessageFormattedTimestamp: String? let unreadNotificationCount: UInt + let notificationMode: RoomNotificationModeProxy? let canonicalAlias: String? let inviter: RoomMemberProxyProtocol? } diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index 41253253d..d58fa05be 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -23,6 +23,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { private let eventStringBuilder: RoomEventStringBuilder private let name: String private var appSettings: AppSettings + private let notificationSettings: NotificationSettingsProxyProtocol private let backgroundTaskService: BackgroundTaskServiceProtocol private let serialDispatchQueue: DispatchQueue @@ -58,18 +59,24 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { eventStringBuilder: RoomEventStringBuilder, name: String, appSettings: AppSettings, + notificationSettings: NotificationSettingsProxyProtocol, backgroundTaskService: BackgroundTaskServiceProtocol) { self.roomListService = roomListService serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomsummaryprovider", qos: .default) self.eventStringBuilder = eventStringBuilder self.name = name self.appSettings = appSettings + self.notificationSettings = notificationSettings self.backgroundTaskService = backgroundTaskService diffsPublisher .receive(on: serialDispatchQueue) .sink { [weak self] in self?.updateRoomsWithDiffs($0) } .store(in: &cancellables) + + if appSettings.notificationSettingsEnabled { + setupNotificationSettingsSubscription() + } } func setRoomList(_ roomList: RoomList) { @@ -227,6 +234,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { inviterProxy = RoomMemberProxy(member: inviter, backgroundTaskService: backgroundTaskService) } + let notificationMode = roomInfo.notificationMode.flatMap { RoomNotificationModeProxy.from(roomNotificationMode: $0) } + let details = RoomSummaryDetails(id: roomInfo.id, name: roomInfo.name ?? roomInfo.id, isDirect: roomInfo.isDirect, @@ -234,6 +243,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { lastMessage: attributedLastMessage, lastMessageFormattedTimestamp: lastMessageFormattedTimestamp, unreadNotificationCount: UInt(roomInfo.notificationCount), + notificationMode: notificationMode, canonicalAlias: roomInfo.canonicalAlias, inviter: inviterProxy) @@ -324,6 +334,43 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { return CollectionDifference(changes) } + + private func setupNotificationSettingsSubscription() { + notificationSettings.callbacks + .receive(on: serialDispatchQueue) + .dropFirst() // drop the first one to avoid rebuilding the summaries during the first synchronization + .sink { [weak self] callback in + guard let self else { return } + switch callback { + case .settingsDidChange: + self.rebuildRoomSummaries() + } + } + .store(in: &cancellables) + } + + private func rebuildRoomSummaries() { + let span = MXLog.createSpan("\(name).rebuild_room_summaries") + span.enter() + defer { + span.exit() + } + + MXLog.info("\(name): Rebuilding room summaries for \(rooms.count) rooms") + + rooms = rooms.map { + switch $0 { + case .empty: + return $0 + case .filled(let details): + return self.buildRoomSummaryForIdentifier(details.id, invalidated: false) + case .invalidated(let details): + return self.buildRoomSummaryForIdentifier(details.id, invalidated: true) + } + } + + MXLog.info("\(name): Finished rebuilding room summaries (\(rooms.count) rooms)") + } } extension RoomSummaryProviderState { diff --git a/UnitTests/Sources/LoggingTests.swift b/UnitTests/Sources/LoggingTests.swift index 83763b19c..9086a9cc7 100644 --- a/UnitTests/Sources/LoggingTests.swift +++ b/UnitTests/Sources/LoggingTests.swift @@ -227,6 +227,7 @@ class LoggingTests: XCTestCase { lastMessage: AttributedString(lastMessage), lastMessageFormattedTimestamp: "Now", unreadNotificationCount: 0, + notificationMode: nil, canonicalAlias: nil, inviter: nil)