mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Display the notification mode for each room in the the room list (#1595)
Co-authored-by: Stefan Ceriu <stefan.ceriu@gmail.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
"Notification" = "Notification";
|
"Notification" = "Notification";
|
||||||
"a11y_hide_password" = "Hide password";
|
"a11y_hide_password" = "Hide password";
|
||||||
|
"a11y_notifications_mentions_only" = "Mentions only";
|
||||||
|
"a11y_notifications_muted" = "Muted";
|
||||||
"a11y_send_files" = "Send files";
|
"a11y_send_files" = "Send files";
|
||||||
"a11y_show_password" = "Show password";
|
"a11y_show_password" = "Show password";
|
||||||
"a11y_user_menu" = "User menu";
|
"a11y_user_menu" = "User menu";
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case (.roomDetails, .presentNotificationSettingsScreen, .notificationSettingsScreen):
|
case (.roomDetails, .presentNotificationSettingsScreen, .notificationSettingsScreen):
|
||||||
asyncPresentNotificationSettingsScreen(animated: animated)
|
presentNotificationSettingsScreen(animated: animated)
|
||||||
case (.notificationSettingsScreen, .dismissNotificationSettingsScreen, .roomDetails):
|
case (.notificationSettingsScreen, .dismissNotificationSettingsScreen, .roomDetails):
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -397,13 +397,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let params = await RoomDetailsScreenCoordinatorParameters(accountUserID: userSession.userID,
|
let params = RoomDetailsScreenCoordinatorParameters(accountUserID: userSession.userID,
|
||||||
navigationStackCoordinator: navigationStackCoordinator,
|
navigationStackCoordinator: navigationStackCoordinator,
|
||||||
roomProxy: roomProxy,
|
roomProxy: roomProxy,
|
||||||
mediaProvider: userSession.mediaProvider,
|
mediaProvider: userSession.mediaProvider,
|
||||||
userDiscoveryService: UserDiscoveryService(clientProxy: userSession.clientProxy),
|
userDiscoveryService: UserDiscoveryService(clientProxy: userSession.clientProxy),
|
||||||
userIndicatorController: userIndicatorController,
|
userIndicatorController: userIndicatorController,
|
||||||
notificationSettings: userSession.clientProxy.notificationSettings())
|
notificationSettings: userSession.clientProxy.notificationSettings)
|
||||||
let coordinator = RoomDetailsScreenCoordinator(parameters: params)
|
let coordinator = RoomDetailsScreenCoordinator(parameters: params)
|
||||||
coordinator.actions.sink { [weak self] action in
|
coordinator.actions.sink { [weak self] action in
|
||||||
switch action {
|
switch action {
|
||||||
@@ -691,19 +691,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
stateMachine.tryEvent(.presentRoom(roomID: roomID), userInfo: EventUserInfo(animated: true, destinationRoomProxy: targetRoomProxy))
|
stateMachine.tryEvent(.presentRoom(roomID: roomID), userInfo: EventUserInfo(animated: true, destinationRoomProxy: targetRoomProxy))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func asyncPresentNotificationSettingsScreen(animated: Bool) {
|
private func presentNotificationSettingsScreen(animated: Bool) {
|
||||||
Task {
|
|
||||||
await presentNotificationSettingsScreen(animated: animated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentNotificationSettingsScreen(animated: Bool) async {
|
|
||||||
let navigationCoordinator = NavigationStackCoordinator()
|
let navigationCoordinator = NavigationStackCoordinator()
|
||||||
let parameters = await NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationCoordinator,
|
let parameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationCoordinator,
|
||||||
userSession: userSession,
|
userSession: userSession,
|
||||||
userNotificationCenter: UNUserNotificationCenter.current(),
|
userNotificationCenter: UNUserNotificationCenter.current(),
|
||||||
notificationSettings: userSession.clientProxy.notificationSettings(),
|
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||||
isModallyPresented: true)
|
isModallyPresented: true)
|
||||||
let coordinator = NotificationSettingsScreenCoordinator(parameters: parameters)
|
let coordinator = NotificationSettingsScreenCoordinator(parameters: parameters)
|
||||||
coordinator.actions.sink { [weak self] action in
|
coordinator.actions.sink { [weak self] action in
|
||||||
switch action {
|
switch action {
|
||||||
|
|||||||
@@ -297,22 +297,16 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
// MARK: Settings
|
// MARK: Settings
|
||||||
|
|
||||||
private func presentSettingsScreen(animated: Bool) {
|
private func presentSettingsScreen(animated: Bool) {
|
||||||
Task {
|
|
||||||
await asyncPresentSettingsScreen(animated: animated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func asyncPresentSettingsScreen(animated: Bool) async {
|
|
||||||
let settingsNavigationStackCoordinator = NavigationStackCoordinator()
|
let settingsNavigationStackCoordinator = NavigationStackCoordinator()
|
||||||
|
|
||||||
let userIndicatorController = UserIndicatorController(rootCoordinator: settingsNavigationStackCoordinator)
|
let userIndicatorController = UserIndicatorController(rootCoordinator: settingsNavigationStackCoordinator)
|
||||||
|
|
||||||
let parameters = await SettingsScreenCoordinatorParameters(navigationStackCoordinator: settingsNavigationStackCoordinator,
|
let parameters = SettingsScreenCoordinatorParameters(navigationStackCoordinator: settingsNavigationStackCoordinator,
|
||||||
userIndicatorController: userIndicatorController,
|
userIndicatorController: userIndicatorController,
|
||||||
userSession: userSession,
|
userSession: userSession,
|
||||||
bugReportService: bugReportService,
|
bugReportService: bugReportService,
|
||||||
notificationSettings: userSession.clientProxy.notificationSettings(),
|
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||||
appSettings: appSettings)
|
appSettings: appSettings)
|
||||||
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters)
|
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters)
|
||||||
settingsScreenCoordinator.callback = { [weak self] action in
|
settingsScreenCoordinator.callback = { [weak self] action in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ import Foundation
|
|||||||
public enum L10n {
|
public enum L10n {
|
||||||
/// Hide password
|
/// Hide password
|
||||||
public static var a11yHidePassword: String { return L10n.tr("Localizable", "a11y_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
|
/// Send files
|
||||||
public static var a11ySendFiles: String { return L10n.tr("Localizable", "a11y_send_files") }
|
public static var a11ySendFiles: String { return L10n.tr("Localizable", "a11y_send_files") }
|
||||||
/// Show password
|
/// Show password
|
||||||
|
|||||||
@@ -139,6 +139,14 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
|||||||
|
|
||||||
var avatarURL: URL?
|
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
|
var isPlaceholder = false
|
||||||
|
|
||||||
static func placeholder() -> HomeScreenRoom {
|
static func placeholder() -> HomeScreenRoom {
|
||||||
|
|||||||
@@ -266,13 +266,16 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
private func buildRoom(with details: RoomSummaryDetails, invalidated: Bool) -> HomeScreenRoom {
|
private func buildRoom(with details: RoomSummaryDetails, invalidated: Bool) -> HomeScreenRoom {
|
||||||
let identifier = invalidated ? "invalidated-" + details.id : details.id
|
let identifier = invalidated ? "invalidated-" + details.id : details.id
|
||||||
|
|
||||||
|
let notificationMode = details.notificationMode == .allMessages || appSettings.notificationSettingsEnabled == false ? nil : details.notificationMode
|
||||||
|
|
||||||
return HomeScreenRoom(id: identifier,
|
return HomeScreenRoom(id: identifier,
|
||||||
roomId: details.id,
|
roomId: details.id,
|
||||||
name: details.name,
|
name: details.name,
|
||||||
hasUnreads: details.unreadNotificationCount > 0,
|
hasUnreads: details.unreadNotificationCount > 0,
|
||||||
timestamp: details.lastMessageFormattedTimestamp,
|
timestamp: details.lastMessageFormattedTimestamp,
|
||||||
lastMessage: .init(attributedString: details.lastMessage, isLoading: false),
|
lastMessage: .init(attributedString: details.lastMessage, isLoading: false),
|
||||||
avatarURL: details.avatarURL)
|
avatarURL: details.avatarURL,
|
||||||
|
notificationMode: notificationMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateVisibleRange(_ range: Range<Int>) {
|
private func updateVisibleRange(_ range: Range<Int>) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Compound
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct HomeScreenRoomCell: View {
|
struct HomeScreenRoomCell: View {
|
||||||
@@ -115,17 +116,42 @@ struct HomeScreenRoomCell: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if room.hasUnreads {
|
HStack(spacing: 8) {
|
||||||
Circle()
|
if let notificationMode = room.notificationMode {
|
||||||
.frame(width: 12, height: 12)
|
notificationModeIcon
|
||||||
.foregroundColor(.compound.iconAccentTertiary)
|
.foregroundColor(room.hasUnreads ? .compound.iconAccentTertiary : .compound.iconQuaternary)
|
||||||
.padding(.leading, 12)
|
}
|
||||||
} else {
|
|
||||||
// Force extra padding between last message text and the right border of the screen if there is no unread dot
|
if room.hasUnreads {
|
||||||
Circle()
|
Circle()
|
||||||
.frame(width: 12, height: 12)
|
.frame(width: 12, height: 12)
|
||||||
.hidden()
|
.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,
|
hasUnreads: details.unreadNotificationCount > 0,
|
||||||
timestamp: Date.now.formattedMinimal(),
|
timestamp: Date.now.formattedMinimal(),
|
||||||
lastMessage: .init(attributedString: details.lastMessage,
|
lastMessage: .init(attributedString: details.lastMessage,
|
||||||
isLoading: false))
|
isLoading: false),
|
||||||
|
notificationMode: details.notificationMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ private extension InvitesScreenRoomDetails {
|
|||||||
lastMessage: nil,
|
lastMessage: nil,
|
||||||
lastMessageFormattedTimestamp: nil,
|
lastMessageFormattedTimestamp: nil,
|
||||||
unreadNotificationCount: 0,
|
unreadNotificationCount: 0,
|
||||||
|
notificationMode: nil,
|
||||||
canonicalAlias: "#footest:somewhere.org",
|
canonicalAlias: "#footest:somewhere.org",
|
||||||
inviter: inviter)
|
inviter: inviter)
|
||||||
return .init(roomDetails: dmRoom, isUnread: false)
|
return .init(roomDetails: dmRoom, isUnread: false)
|
||||||
@@ -207,6 +208,7 @@ private extension InvitesScreenRoomDetails {
|
|||||||
lastMessage: nil,
|
lastMessage: nil,
|
||||||
lastMessageFormattedTimestamp: nil,
|
lastMessageFormattedTimestamp: nil,
|
||||||
unreadNotificationCount: 0,
|
unreadNotificationCount: 0,
|
||||||
|
notificationMode: nil,
|
||||||
canonicalAlias: alias,
|
canonicalAlias: alias,
|
||||||
inviter: inviter)
|
inviter: inviter)
|
||||||
return .init(roomDetails: dmRoom, isUnread: isUnread)
|
return .init(roomDetails: dmRoom, isUnread: isUnread)
|
||||||
|
|||||||
+1
@@ -50,6 +50,7 @@ struct DeveloperOptionsScreen: View {
|
|||||||
Section("Notifications") {
|
Section("Notifications") {
|
||||||
Toggle(isOn: $context.notificationSettingsEnabled) {
|
Toggle(isOn: $context.notificationSettingsEnabled) {
|
||||||
Text("Show notification settings")
|
Text("Show notification settings")
|
||||||
|
Text("Requires app reboot")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
|
|
||||||
var roomSummaryProvider: RoomSummaryProviderProtocol?
|
var roomSummaryProvider: RoomSummaryProviderProtocol?
|
||||||
var inviteSummaryProvider: RoomSummaryProviderProtocol?
|
var inviteSummaryProvider: RoomSummaryProviderProtocol?
|
||||||
|
|
||||||
|
var notificationSettings: NotificationSettingsProxyProtocol
|
||||||
|
|
||||||
private let roomListRecencyOrderingAllowedEventTypes = ["m.room.message", "m.room.encrypted", "m.sticker"]
|
private let roomListRecencyOrderingAllowedEventTypes = ["m.room.message", "m.room.encrypted", "m.sticker"]
|
||||||
|
|
||||||
@@ -66,6 +68,9 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
clientQueue = .init(label: "ClientProxyQueue", attributes: .concurrent)
|
clientQueue = .init(label: "ClientProxyQueue", attributes: .concurrent)
|
||||||
|
|
||||||
mediaLoader = MediaLoader(client: client, clientQueue: clientQueue)
|
mediaLoader = MediaLoader(client: client, clientQueue: clientQueue)
|
||||||
|
|
||||||
|
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings(),
|
||||||
|
backgroundTaskService: backgroundTaskService)
|
||||||
|
|
||||||
client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in
|
client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in
|
||||||
self?.callbacks.send(.receivedAuthError(isSoftLogout: isSoftLogout))
|
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
|
// MARK: Private
|
||||||
|
|
||||||
private func restartSync(delay: Duration = .zero) {
|
private func restartSync(delay: Duration = .zero) {
|
||||||
@@ -405,12 +403,14 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
eventStringBuilder: eventStringBuilder,
|
eventStringBuilder: eventStringBuilder,
|
||||||
name: "AllRooms",
|
name: "AllRooms",
|
||||||
appSettings: appSettings,
|
appSettings: appSettings,
|
||||||
|
notificationSettings: notificationSettings,
|
||||||
backgroundTaskService: backgroundTaskService)
|
backgroundTaskService: backgroundTaskService)
|
||||||
try await roomSummaryProvider?.setRoomList(roomListService.allRooms())
|
try await roomSummaryProvider?.setRoomList(roomListService.allRooms())
|
||||||
inviteSummaryProvider = RoomSummaryProvider(roomListService: roomListService,
|
inviteSummaryProvider = RoomSummaryProvider(roomListService: roomListService,
|
||||||
eventStringBuilder: eventStringBuilder,
|
eventStringBuilder: eventStringBuilder,
|
||||||
name: "Invites",
|
name: "Invites",
|
||||||
appSettings: appSettings,
|
appSettings: appSettings,
|
||||||
|
notificationSettings: notificationSettings,
|
||||||
backgroundTaskService: backgroundTaskService)
|
backgroundTaskService: backgroundTaskService)
|
||||||
|
|
||||||
self.syncService = syncService
|
self.syncService = syncService
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
|||||||
|
|
||||||
var inviteSummaryProvider: RoomSummaryProviderProtocol? { get }
|
var inviteSummaryProvider: RoomSummaryProviderProtocol? { get }
|
||||||
|
|
||||||
|
var notificationSettings: NotificationSettingsProxyProtocol { get }
|
||||||
|
|
||||||
func startSync()
|
func startSync()
|
||||||
|
|
||||||
func stopSync()
|
func stopSync()
|
||||||
@@ -114,6 +116,4 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
|||||||
func searchUsers(searchTerm: String, limit: UInt) async -> Result<SearchUsersResultsProxy, ClientProxyError>
|
func searchUsers(searchTerm: String, limit: UInt) async -> Result<SearchUsersResultsProxy, ClientProxyError>
|
||||||
|
|
||||||
func profile(for userID: String) async -> Result<UserProfileProxy, ClientProxyError>
|
func profile(for userID: String) async -> Result<UserProfileProxy, ClientProxyError>
|
||||||
|
|
||||||
func notificationSettings() async -> NotificationSettingsProxyProtocol
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ class MockClientProxy: ClientProxyProtocol {
|
|||||||
var inviteSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider()
|
var inviteSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider()
|
||||||
|
|
||||||
var avatarURLPublisher: AnyPublisher<URL?, Never> { Empty().eraseToAnyPublisher() }
|
var avatarURLPublisher: AnyPublisher<URL?, Never> { Empty().eraseToAnyPublisher() }
|
||||||
|
|
||||||
|
var notificationSettings: NotificationSettingsProxyProtocol = NotificationSettingsProxyMock(with: .init())
|
||||||
|
|
||||||
init(userID: String, deviceID: String? = nil, accountURL: URL? = nil, roomSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider()) {
|
init(userID: String, deviceID: String? = nil, accountURL: URL? = nil, roomSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider()) {
|
||||||
self.userID = userID
|
self.userID = userID
|
||||||
@@ -141,13 +143,4 @@ class MockClientProxy: ClientProxyProtocol {
|
|||||||
getProfileCalled = true
|
getProfileCalled = true
|
||||||
return getProfileResult
|
return getProfileResult
|
||||||
}
|
}
|
||||||
|
|
||||||
var notificationSettingsResult: NotificationSettingsProxyProtocol?
|
|
||||||
func notificationSettings() -> NotificationSettingsProxyProtocol {
|
|
||||||
if let notificationSettingsResult {
|
|
||||||
return notificationSettingsResult
|
|
||||||
} else {
|
|
||||||
return NotificationSettingsProxyMock(with: .init())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ private final class WeakNotificationSettingsProxy: NotificationSettingsDelegate
|
|||||||
final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||||
private(set) var notificationSettings: MatrixRustSDK.NotificationSettingsProtocol
|
private(set) var notificationSettings: MatrixRustSDK.NotificationSettingsProtocol
|
||||||
private let backgroundTaskService: BackgroundTaskServiceProtocol?
|
private let backgroundTaskService: BackgroundTaskServiceProtocol?
|
||||||
|
|
||||||
let callbacks = PassthroughSubject<NotificationSettingsProxyCallback, Never>()
|
let callbacks = PassthroughSubject<NotificationSettingsProxyCallback, Never>()
|
||||||
|
|
||||||
init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol, backgroundTaskService: BackgroundTaskServiceProtocol?) {
|
init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol, backgroundTaskService: BackgroundTaskServiceProtocol?) {
|
||||||
|
|||||||
@@ -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."),
|
lastMessage: AttributedString("Prosciutto beef ribs pancetta filet mignon kevin hamburger, chuck ham venison picanha. Beef ribs chislic turkey biltong tenderloin."),
|
||||||
lastMessageFormattedTimestamp: "Now",
|
lastMessageFormattedTimestamp: "Now",
|
||||||
unreadNotificationCount: 4,
|
unreadNotificationCount: 4,
|
||||||
|
notificationMode: .allMessages,
|
||||||
canonicalAlias: nil,
|
canonicalAlias: nil,
|
||||||
inviter: RoomMemberProxyMock.mockCharlie)),
|
inviter: RoomMemberProxyMock.mockCharlie)),
|
||||||
.filled(details: RoomSummaryDetails(id: "2",
|
.filled(details: RoomSummaryDetails(id: "2",
|
||||||
@@ -66,6 +67,7 @@ extension Array where Element == RoomSummary {
|
|||||||
lastMessage: nil,
|
lastMessage: nil,
|
||||||
lastMessageFormattedTimestamp: nil,
|
lastMessageFormattedTimestamp: nil,
|
||||||
unreadNotificationCount: 1,
|
unreadNotificationCount: 1,
|
||||||
|
notificationMode: .mentionsAndKeywordsOnly,
|
||||||
canonicalAlias: nil,
|
canonicalAlias: nil,
|
||||||
inviter: RoomMemberProxyMock.mockCharlie)),
|
inviter: RoomMemberProxyMock.mockCharlie)),
|
||||||
.filled(details: RoomSummaryDetails(id: "3",
|
.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"),
|
lastMessage: try? AttributedString(markdown: "**@mock:client.com**: T-bone beef ribs bacon"),
|
||||||
lastMessageFormattedTimestamp: "Later",
|
lastMessageFormattedTimestamp: "Later",
|
||||||
unreadNotificationCount: 0,
|
unreadNotificationCount: 0,
|
||||||
|
notificationMode: .mute,
|
||||||
canonicalAlias: nil,
|
canonicalAlias: nil,
|
||||||
inviter: RoomMemberProxyMock.mockCharlie)),
|
inviter: RoomMemberProxyMock.mockCharlie)),
|
||||||
.empty
|
.empty
|
||||||
@@ -87,6 +90,7 @@ extension Array where Element == RoomSummary {
|
|||||||
lastMessage: nil,
|
lastMessage: nil,
|
||||||
lastMessageFormattedTimestamp: nil,
|
lastMessageFormattedTimestamp: nil,
|
||||||
unreadNotificationCount: 0,
|
unreadNotificationCount: 0,
|
||||||
|
notificationMode: nil,
|
||||||
canonicalAlias: "#footest:somewhere.org",
|
canonicalAlias: "#footest:somewhere.org",
|
||||||
inviter: RoomMemberProxyMock.mockCharlie)),
|
inviter: RoomMemberProxyMock.mockCharlie)),
|
||||||
.filled(details: RoomSummaryDetails(id: "someAwesomeRoomId2",
|
.filled(details: RoomSummaryDetails(id: "someAwesomeRoomId2",
|
||||||
@@ -96,6 +100,7 @@ extension Array where Element == RoomSummary {
|
|||||||
lastMessage: nil,
|
lastMessage: nil,
|
||||||
lastMessageFormattedTimestamp: nil,
|
lastMessageFormattedTimestamp: nil,
|
||||||
unreadNotificationCount: 0,
|
unreadNotificationCount: 0,
|
||||||
|
notificationMode: nil,
|
||||||
canonicalAlias: nil,
|
canonicalAlias: nil,
|
||||||
inviter: RoomMemberProxyMock.mockCharlie))
|
inviter: RoomMemberProxyMock.mockCharlie))
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ struct RoomSummaryDetails {
|
|||||||
let lastMessage: AttributedString?
|
let lastMessage: AttributedString?
|
||||||
let lastMessageFormattedTimestamp: String?
|
let lastMessageFormattedTimestamp: String?
|
||||||
let unreadNotificationCount: UInt
|
let unreadNotificationCount: UInt
|
||||||
|
let notificationMode: RoomNotificationModeProxy?
|
||||||
let canonicalAlias: String?
|
let canonicalAlias: String?
|
||||||
let inviter: RoomMemberProxyProtocol?
|
let inviter: RoomMemberProxyProtocol?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
|||||||
private let eventStringBuilder: RoomEventStringBuilder
|
private let eventStringBuilder: RoomEventStringBuilder
|
||||||
private let name: String
|
private let name: String
|
||||||
private var appSettings: AppSettings
|
private var appSettings: AppSettings
|
||||||
|
private let notificationSettings: NotificationSettingsProxyProtocol
|
||||||
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
||||||
|
|
||||||
private let serialDispatchQueue: DispatchQueue
|
private let serialDispatchQueue: DispatchQueue
|
||||||
@@ -58,18 +59,24 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
|||||||
eventStringBuilder: RoomEventStringBuilder,
|
eventStringBuilder: RoomEventStringBuilder,
|
||||||
name: String,
|
name: String,
|
||||||
appSettings: AppSettings,
|
appSettings: AppSettings,
|
||||||
|
notificationSettings: NotificationSettingsProxyProtocol,
|
||||||
backgroundTaskService: BackgroundTaskServiceProtocol) {
|
backgroundTaskService: BackgroundTaskServiceProtocol) {
|
||||||
self.roomListService = roomListService
|
self.roomListService = roomListService
|
||||||
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomsummaryprovider", qos: .default)
|
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomsummaryprovider", qos: .default)
|
||||||
self.eventStringBuilder = eventStringBuilder
|
self.eventStringBuilder = eventStringBuilder
|
||||||
self.name = name
|
self.name = name
|
||||||
self.appSettings = appSettings
|
self.appSettings = appSettings
|
||||||
|
self.notificationSettings = notificationSettings
|
||||||
self.backgroundTaskService = backgroundTaskService
|
self.backgroundTaskService = backgroundTaskService
|
||||||
|
|
||||||
diffsPublisher
|
diffsPublisher
|
||||||
.receive(on: serialDispatchQueue)
|
.receive(on: serialDispatchQueue)
|
||||||
.sink { [weak self] in self?.updateRoomsWithDiffs($0) }
|
.sink { [weak self] in self?.updateRoomsWithDiffs($0) }
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
if appSettings.notificationSettingsEnabled {
|
||||||
|
setupNotificationSettingsSubscription()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRoomList(_ roomList: RoomList) {
|
func setRoomList(_ roomList: RoomList) {
|
||||||
@@ -227,6 +234,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
|||||||
inviterProxy = RoomMemberProxy(member: inviter, backgroundTaskService: backgroundTaskService)
|
inviterProxy = RoomMemberProxy(member: inviter, backgroundTaskService: backgroundTaskService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let notificationMode = roomInfo.notificationMode.flatMap { RoomNotificationModeProxy.from(roomNotificationMode: $0) }
|
||||||
|
|
||||||
let details = RoomSummaryDetails(id: roomInfo.id,
|
let details = RoomSummaryDetails(id: roomInfo.id,
|
||||||
name: roomInfo.name ?? roomInfo.id,
|
name: roomInfo.name ?? roomInfo.id,
|
||||||
isDirect: roomInfo.isDirect,
|
isDirect: roomInfo.isDirect,
|
||||||
@@ -234,6 +243,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
|||||||
lastMessage: attributedLastMessage,
|
lastMessage: attributedLastMessage,
|
||||||
lastMessageFormattedTimestamp: lastMessageFormattedTimestamp,
|
lastMessageFormattedTimestamp: lastMessageFormattedTimestamp,
|
||||||
unreadNotificationCount: UInt(roomInfo.notificationCount),
|
unreadNotificationCount: UInt(roomInfo.notificationCount),
|
||||||
|
notificationMode: notificationMode,
|
||||||
canonicalAlias: roomInfo.canonicalAlias,
|
canonicalAlias: roomInfo.canonicalAlias,
|
||||||
inviter: inviterProxy)
|
inviter: inviterProxy)
|
||||||
|
|
||||||
@@ -324,6 +334,43 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
|||||||
|
|
||||||
return CollectionDifference(changes)
|
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 {
|
extension RoomSummaryProviderState {
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ class LoggingTests: XCTestCase {
|
|||||||
lastMessage: AttributedString(lastMessage),
|
lastMessage: AttributedString(lastMessage),
|
||||||
lastMessageFormattedTimestamp: "Now",
|
lastMessageFormattedTimestamp: "Now",
|
||||||
unreadNotificationCount: 0,
|
unreadNotificationCount: 0,
|
||||||
|
notificationMode: nil,
|
||||||
canonicalAlias: nil,
|
canonicalAlias: nil,
|
||||||
inviter: nil)
|
inviter: nil)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user