mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Add a "Mute" shortcut and a "Notifications" section in the room details screen #1318
This commit is contained in:
@@ -364,12 +364,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
return
|
||||
}
|
||||
|
||||
let params = RoomDetailsScreenCoordinatorParameters(accountUserID: userSession.userID,
|
||||
navigationStackCoordinator: navigationStackCoordinator,
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: userSession.mediaProvider,
|
||||
userDiscoveryService: UserDiscoveryService(clientProxy: userSession.clientProxy),
|
||||
userIndicatorController: userIndicatorController)
|
||||
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 coordinator = RoomDetailsScreenCoordinator(parameters: params)
|
||||
coordinator.callback = { [weak self] action in
|
||||
switch action {
|
||||
|
||||
@@ -724,10 +724,20 @@ public enum L10n {
|
||||
public static var screenRoomDetailsEncryptionEnabledSubtitle: String { return L10n.tr("Localizable", "screen_room_details_encryption_enabled_subtitle") }
|
||||
/// Message encryption enabled
|
||||
public static var screenRoomDetailsEncryptionEnabledTitle: String { return L10n.tr("Localizable", "screen_room_details_encryption_enabled_title") }
|
||||
/// An error occurred when loading notification settings.
|
||||
public static var screenRoomDetailsErrorLoadingNotificationSettings: String { return L10n.tr("Localizable", "screen_room_details_error_loading_notification_settings") }
|
||||
/// Failed muting this room, please try again.
|
||||
public static var screenRoomDetailsErrorMuting: String { return L10n.tr("Localizable", "screen_room_details_error_muting") }
|
||||
/// Failed unmuting this room, please try again.
|
||||
public static var screenRoomDetailsErrorUnmuting: String { return L10n.tr("Localizable", "screen_room_details_error_unmuting") }
|
||||
/// Invite people
|
||||
public static var screenRoomDetailsInvitePeopleTitle: String { return L10n.tr("Localizable", "screen_room_details_invite_people_title") }
|
||||
/// Leave room
|
||||
public static var screenRoomDetailsLeaveRoomTitle: String { return L10n.tr("Localizable", "screen_room_details_leave_room_title") }
|
||||
/// Custom
|
||||
public static var screenRoomDetailsNotificationModeCustom: String { return L10n.tr("Localizable", "screen_room_details_notification_mode_custom") }
|
||||
/// Default
|
||||
public static var screenRoomDetailsNotificationModeDefault: String { return L10n.tr("Localizable", "screen_room_details_notification_mode_default") }
|
||||
/// Notifications
|
||||
public static var screenRoomDetailsNotificationTitle: String { return L10n.tr("Localizable", "screen_room_details_notification_title") }
|
||||
/// People
|
||||
|
||||
@@ -313,6 +313,260 @@ class NotificationManagerMock: NotificationManagerProtocol {
|
||||
requestAuthorizationClosure?()
|
||||
}
|
||||
}
|
||||
class NotificationSettingsProxyMock: NotificationSettingsProxyProtocol {
|
||||
var callbacks: PassthroughSubject<NotificationSettingsProxyCallback, Never> {
|
||||
get { return underlyingCallbacks }
|
||||
set(value) { underlyingCallbacks = value }
|
||||
}
|
||||
var underlyingCallbacks: PassthroughSubject<NotificationSettingsProxyCallback, Never>!
|
||||
|
||||
//MARK: - getNotificationSettings
|
||||
|
||||
var getNotificationSettingsRoomIdIsEncryptedActiveMembersCountThrowableError: Error?
|
||||
var getNotificationSettingsRoomIdIsEncryptedActiveMembersCountCallsCount = 0
|
||||
var getNotificationSettingsRoomIdIsEncryptedActiveMembersCountCalled: Bool {
|
||||
return getNotificationSettingsRoomIdIsEncryptedActiveMembersCountCallsCount > 0
|
||||
}
|
||||
var getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReceivedArguments: (roomId: String, isEncrypted: Bool, activeMembersCount: UInt64)?
|
||||
var getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReceivedInvocations: [(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64)] = []
|
||||
var getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReturnValue: RoomNotificationSettingsProxyProtocol!
|
||||
var getNotificationSettingsRoomIdIsEncryptedActiveMembersCountClosure: ((String, Bool, UInt64) async throws -> RoomNotificationSettingsProxyProtocol)?
|
||||
|
||||
func getNotificationSettings(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64) async throws -> RoomNotificationSettingsProxyProtocol {
|
||||
if let error = getNotificationSettingsRoomIdIsEncryptedActiveMembersCountThrowableError {
|
||||
throw error
|
||||
}
|
||||
getNotificationSettingsRoomIdIsEncryptedActiveMembersCountCallsCount += 1
|
||||
getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReceivedArguments = (roomId: roomId, isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReceivedInvocations.append((roomId: roomId, isEncrypted: isEncrypted, activeMembersCount: activeMembersCount))
|
||||
if let getNotificationSettingsRoomIdIsEncryptedActiveMembersCountClosure = getNotificationSettingsRoomIdIsEncryptedActiveMembersCountClosure {
|
||||
return try await getNotificationSettingsRoomIdIsEncryptedActiveMembersCountClosure(roomId, isEncrypted, activeMembersCount)
|
||||
} else {
|
||||
return getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - setNotificationMode
|
||||
|
||||
var setNotificationModeRoomIdModeThrowableError: Error?
|
||||
var setNotificationModeRoomIdModeCallsCount = 0
|
||||
var setNotificationModeRoomIdModeCalled: Bool {
|
||||
return setNotificationModeRoomIdModeCallsCount > 0
|
||||
}
|
||||
var setNotificationModeRoomIdModeReceivedArguments: (roomId: String, mode: RoomNotificationMode)?
|
||||
var setNotificationModeRoomIdModeReceivedInvocations: [(roomId: String, mode: RoomNotificationMode)] = []
|
||||
var setNotificationModeRoomIdModeClosure: ((String, RoomNotificationMode) async throws -> Void)?
|
||||
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationMode) async throws {
|
||||
if let error = setNotificationModeRoomIdModeThrowableError {
|
||||
throw error
|
||||
}
|
||||
setNotificationModeRoomIdModeCallsCount += 1
|
||||
setNotificationModeRoomIdModeReceivedArguments = (roomId: roomId, mode: mode)
|
||||
setNotificationModeRoomIdModeReceivedInvocations.append((roomId: roomId, mode: mode))
|
||||
try await setNotificationModeRoomIdModeClosure?(roomId, mode)
|
||||
}
|
||||
//MARK: - getDefaultNotificationRoomMode
|
||||
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountCallsCount = 0
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountCalled: Bool {
|
||||
return getDefaultNotificationRoomModeIsEncryptedActiveMembersCountCallsCount > 0
|
||||
}
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedArguments: (isEncrypted: Bool, activeMembersCount: UInt64)?
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedInvocations: [(isEncrypted: Bool, activeMembersCount: UInt64)] = []
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReturnValue: RoomNotificationMode!
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountClosure: ((Bool, UInt64) async -> RoomNotificationMode)?
|
||||
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationMode {
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountCallsCount += 1
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedArguments = (isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedInvocations.append((isEncrypted: isEncrypted, activeMembersCount: activeMembersCount))
|
||||
if let getDefaultNotificationRoomModeIsEncryptedActiveMembersCountClosure = getDefaultNotificationRoomModeIsEncryptedActiveMembersCountClosure {
|
||||
return await getDefaultNotificationRoomModeIsEncryptedActiveMembersCountClosure(isEncrypted, activeMembersCount)
|
||||
} else {
|
||||
return getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - restoreDefaultNotificationMode
|
||||
|
||||
var restoreDefaultNotificationModeRoomIdThrowableError: Error?
|
||||
var restoreDefaultNotificationModeRoomIdCallsCount = 0
|
||||
var restoreDefaultNotificationModeRoomIdCalled: Bool {
|
||||
return restoreDefaultNotificationModeRoomIdCallsCount > 0
|
||||
}
|
||||
var restoreDefaultNotificationModeRoomIdReceivedRoomId: String?
|
||||
var restoreDefaultNotificationModeRoomIdReceivedInvocations: [String] = []
|
||||
var restoreDefaultNotificationModeRoomIdClosure: ((String) async throws -> Void)?
|
||||
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws {
|
||||
if let error = restoreDefaultNotificationModeRoomIdThrowableError {
|
||||
throw error
|
||||
}
|
||||
restoreDefaultNotificationModeRoomIdCallsCount += 1
|
||||
restoreDefaultNotificationModeRoomIdReceivedRoomId = roomId
|
||||
restoreDefaultNotificationModeRoomIdReceivedInvocations.append(roomId)
|
||||
try await restoreDefaultNotificationModeRoomIdClosure?(roomId)
|
||||
}
|
||||
//MARK: - containsKeywordsRules
|
||||
|
||||
var containsKeywordsRulesCallsCount = 0
|
||||
var containsKeywordsRulesCalled: Bool {
|
||||
return containsKeywordsRulesCallsCount > 0
|
||||
}
|
||||
var containsKeywordsRulesReturnValue: Bool!
|
||||
var containsKeywordsRulesClosure: (() async -> Bool)?
|
||||
|
||||
func containsKeywordsRules() async -> Bool {
|
||||
containsKeywordsRulesCallsCount += 1
|
||||
if let containsKeywordsRulesClosure = containsKeywordsRulesClosure {
|
||||
return await containsKeywordsRulesClosure()
|
||||
} else {
|
||||
return containsKeywordsRulesReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - unmuteRoom
|
||||
|
||||
var unmuteRoomRoomIdIsEncryptedActiveMembersCountThrowableError: Error?
|
||||
var unmuteRoomRoomIdIsEncryptedActiveMembersCountCallsCount = 0
|
||||
var unmuteRoomRoomIdIsEncryptedActiveMembersCountCalled: Bool {
|
||||
return unmuteRoomRoomIdIsEncryptedActiveMembersCountCallsCount > 0
|
||||
}
|
||||
var unmuteRoomRoomIdIsEncryptedActiveMembersCountReceivedArguments: (roomId: String, isEncrypted: Bool, activeMembersCount: UInt64)?
|
||||
var unmuteRoomRoomIdIsEncryptedActiveMembersCountReceivedInvocations: [(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64)] = []
|
||||
var unmuteRoomRoomIdIsEncryptedActiveMembersCountClosure: ((String, Bool, UInt64) async throws -> Void)?
|
||||
|
||||
func unmuteRoom(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64) async throws {
|
||||
if let error = unmuteRoomRoomIdIsEncryptedActiveMembersCountThrowableError {
|
||||
throw error
|
||||
}
|
||||
unmuteRoomRoomIdIsEncryptedActiveMembersCountCallsCount += 1
|
||||
unmuteRoomRoomIdIsEncryptedActiveMembersCountReceivedArguments = (roomId: roomId, isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
unmuteRoomRoomIdIsEncryptedActiveMembersCountReceivedInvocations.append((roomId: roomId, isEncrypted: isEncrypted, activeMembersCount: activeMembersCount))
|
||||
try await unmuteRoomRoomIdIsEncryptedActiveMembersCountClosure?(roomId, isEncrypted, activeMembersCount)
|
||||
}
|
||||
//MARK: - isRoomMentionEnabled
|
||||
|
||||
var isRoomMentionEnabledThrowableError: Error?
|
||||
var isRoomMentionEnabledCallsCount = 0
|
||||
var isRoomMentionEnabledCalled: Bool {
|
||||
return isRoomMentionEnabledCallsCount > 0
|
||||
}
|
||||
var isRoomMentionEnabledReturnValue: Bool!
|
||||
var isRoomMentionEnabledClosure: (() async throws -> Bool)?
|
||||
|
||||
func isRoomMentionEnabled() async throws -> Bool {
|
||||
if let error = isRoomMentionEnabledThrowableError {
|
||||
throw error
|
||||
}
|
||||
isRoomMentionEnabledCallsCount += 1
|
||||
if let isRoomMentionEnabledClosure = isRoomMentionEnabledClosure {
|
||||
return try await isRoomMentionEnabledClosure()
|
||||
} else {
|
||||
return isRoomMentionEnabledReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - setRoomMentionEnabled
|
||||
|
||||
var setRoomMentionEnabledEnabledThrowableError: Error?
|
||||
var setRoomMentionEnabledEnabledCallsCount = 0
|
||||
var setRoomMentionEnabledEnabledCalled: Bool {
|
||||
return setRoomMentionEnabledEnabledCallsCount > 0
|
||||
}
|
||||
var setRoomMentionEnabledEnabledReceivedEnabled: Bool?
|
||||
var setRoomMentionEnabledEnabledReceivedInvocations: [Bool] = []
|
||||
var setRoomMentionEnabledEnabledClosure: ((Bool) async throws -> Void)?
|
||||
|
||||
func setRoomMentionEnabled(enabled: Bool) async throws {
|
||||
if let error = setRoomMentionEnabledEnabledThrowableError {
|
||||
throw error
|
||||
}
|
||||
setRoomMentionEnabledEnabledCallsCount += 1
|
||||
setRoomMentionEnabledEnabledReceivedEnabled = enabled
|
||||
setRoomMentionEnabledEnabledReceivedInvocations.append(enabled)
|
||||
try await setRoomMentionEnabledEnabledClosure?(enabled)
|
||||
}
|
||||
//MARK: - isUserMentionEnabled
|
||||
|
||||
var isUserMentionEnabledThrowableError: Error?
|
||||
var isUserMentionEnabledCallsCount = 0
|
||||
var isUserMentionEnabledCalled: Bool {
|
||||
return isUserMentionEnabledCallsCount > 0
|
||||
}
|
||||
var isUserMentionEnabledReturnValue: Bool!
|
||||
var isUserMentionEnabledClosure: (() async throws -> Bool)?
|
||||
|
||||
func isUserMentionEnabled() async throws -> Bool {
|
||||
if let error = isUserMentionEnabledThrowableError {
|
||||
throw error
|
||||
}
|
||||
isUserMentionEnabledCallsCount += 1
|
||||
if let isUserMentionEnabledClosure = isUserMentionEnabledClosure {
|
||||
return try await isUserMentionEnabledClosure()
|
||||
} else {
|
||||
return isUserMentionEnabledReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - setUserMentionEnabled
|
||||
|
||||
var setUserMentionEnabledEnabledThrowableError: Error?
|
||||
var setUserMentionEnabledEnabledCallsCount = 0
|
||||
var setUserMentionEnabledEnabledCalled: Bool {
|
||||
return setUserMentionEnabledEnabledCallsCount > 0
|
||||
}
|
||||
var setUserMentionEnabledEnabledReceivedEnabled: Bool?
|
||||
var setUserMentionEnabledEnabledReceivedInvocations: [Bool] = []
|
||||
var setUserMentionEnabledEnabledClosure: ((Bool) async throws -> Void)?
|
||||
|
||||
func setUserMentionEnabled(enabled: Bool) async throws {
|
||||
if let error = setUserMentionEnabledEnabledThrowableError {
|
||||
throw error
|
||||
}
|
||||
setUserMentionEnabledEnabledCallsCount += 1
|
||||
setUserMentionEnabledEnabledReceivedEnabled = enabled
|
||||
setUserMentionEnabledEnabledReceivedInvocations.append(enabled)
|
||||
try await setUserMentionEnabledEnabledClosure?(enabled)
|
||||
}
|
||||
//MARK: - isCallEnabled
|
||||
|
||||
var isCallEnabledThrowableError: Error?
|
||||
var isCallEnabledCallsCount = 0
|
||||
var isCallEnabledCalled: Bool {
|
||||
return isCallEnabledCallsCount > 0
|
||||
}
|
||||
var isCallEnabledReturnValue: Bool!
|
||||
var isCallEnabledClosure: (() async throws -> Bool)?
|
||||
|
||||
func isCallEnabled() async throws -> Bool {
|
||||
if let error = isCallEnabledThrowableError {
|
||||
throw error
|
||||
}
|
||||
isCallEnabledCallsCount += 1
|
||||
if let isCallEnabledClosure = isCallEnabledClosure {
|
||||
return try await isCallEnabledClosure()
|
||||
} else {
|
||||
return isCallEnabledReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - setCallEnabled
|
||||
|
||||
var setCallEnabledEnabledThrowableError: Error?
|
||||
var setCallEnabledEnabledCallsCount = 0
|
||||
var setCallEnabledEnabledCalled: Bool {
|
||||
return setCallEnabledEnabledCallsCount > 0
|
||||
}
|
||||
var setCallEnabledEnabledReceivedEnabled: Bool?
|
||||
var setCallEnabledEnabledReceivedInvocations: [Bool] = []
|
||||
var setCallEnabledEnabledClosure: ((Bool) async throws -> Void)?
|
||||
|
||||
func setCallEnabled(enabled: Bool) async throws {
|
||||
if let error = setCallEnabledEnabledThrowableError {
|
||||
throw error
|
||||
}
|
||||
setCallEnabledEnabledCallsCount += 1
|
||||
setCallEnabledEnabledReceivedEnabled = enabled
|
||||
setCallEnabledEnabledReceivedInvocations.append(enabled)
|
||||
try await setCallEnabledEnabledClosure?(enabled)
|
||||
}
|
||||
}
|
||||
class RoomMemberProxyMock: RoomMemberProxyProtocol {
|
||||
var userID: String {
|
||||
get { return underlyingUserID }
|
||||
@@ -413,6 +667,19 @@ class RoomMemberProxyMock: RoomMemberProxyProtocol {
|
||||
}
|
||||
}
|
||||
}
|
||||
class RoomNotificationSettingsProxyMock: RoomNotificationSettingsProxyProtocol {
|
||||
var mode: RoomNotificationMode {
|
||||
get { return underlyingMode }
|
||||
set(value) { underlyingMode = value }
|
||||
}
|
||||
var underlyingMode: RoomNotificationMode!
|
||||
var isDefault: Bool {
|
||||
get { return underlyingIsDefault }
|
||||
set(value) { underlyingIsDefault = value }
|
||||
}
|
||||
var underlyingIsDefault: Bool!
|
||||
|
||||
}
|
||||
class RoomProxyMock: RoomProxyProtocol {
|
||||
var id: String {
|
||||
get { return underlyingId }
|
||||
|
||||
@@ -274,6 +274,7 @@ class SDKClientMock: SDKClientProtocol {
|
||||
return getNotificationSettingsReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - `getProfile`
|
||||
|
||||
public var getProfileUserIdThrowableError: Error?
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
struct NotificationSettingsProxyMockConfiguration {
|
||||
var callback = PassthroughSubject<NotificationSettingsProxyCallback, Never>()
|
||||
var defaultRoomMode: RoomNotificationMode = .mentionsAndKeywordsOnly
|
||||
var roomMode = RoomNotificationSettingsProxyMock(with: RoomNotificationSettingsProxyMockConfiguration(mode: .allMessages, isDefault: true))
|
||||
}
|
||||
|
||||
extension NotificationSettingsProxyMock {
|
||||
convenience init(with configuration: NotificationSettingsProxyMockConfiguration) {
|
||||
self.init()
|
||||
|
||||
callbacks = configuration.callback
|
||||
getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReturnValue = configuration.roomMode
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReturnValue = configuration.defaultRoomMode
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
struct RoomNotificationSettingsProxyMockConfiguration {
|
||||
var mode: RoomNotificationMode = .allMessages
|
||||
var isDefault = true
|
||||
}
|
||||
|
||||
extension RoomNotificationSettingsProxyMock {
|
||||
convenience init(with configuration: RoomNotificationSettingsProxyMockConfiguration) {
|
||||
self.init()
|
||||
|
||||
isDefault = configuration.isDefault
|
||||
mode = configuration.mode
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,7 @@ struct A11yIdentifiers {
|
||||
let dmAvatar = "room_details-dm_avatar"
|
||||
let people = "room_details-people"
|
||||
let invite = "room_details-invite"
|
||||
let notifications = "room_details-notifications"
|
||||
}
|
||||
|
||||
struct RoomMemberDetailsScreen {
|
||||
|
||||
@@ -24,6 +24,7 @@ struct RoomDetailsScreenCoordinatorParameters {
|
||||
let mediaProvider: MediaProviderProtocol
|
||||
let userDiscoveryService: UserDiscoveryServiceProtocol
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
let notificationSettings: NotificationSettingsProxyProtocol
|
||||
}
|
||||
|
||||
enum RoomDetailsScreenCoordinatorAction {
|
||||
@@ -47,7 +48,9 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
viewModel = RoomDetailsScreenViewModel(accountUserID: parameters.accountUserID,
|
||||
roomProxy: parameters.roomProxy,
|
||||
mediaProvider: parameters.mediaProvider,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
notificationSettingsProxy: parameters.notificationSettings,
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -65,6 +68,8 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
self.callback?(.leftRoom)
|
||||
case .requestEditDetailsPresentation(let accountOwner):
|
||||
self.presentRoomDetailsEditScreen(accountOwner: accountOwner)
|
||||
case .requestNotificationSettingsPresentation:
|
||||
self.presentNotificationSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,6 +187,8 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
message: L10n.commonUnableToInviteMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private func presentNotificationSettings() { }
|
||||
}
|
||||
|
||||
private extension Result {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
// MARK: - Coordinator
|
||||
@@ -22,6 +23,7 @@ import UIKit
|
||||
// MARK: View model
|
||||
|
||||
enum RoomDetailsScreenViewModelAction {
|
||||
case requestNotificationSettingsPresentation
|
||||
case requestMemberDetailsPresentation
|
||||
case requestInvitePeoplePresentation
|
||||
case leftRoom
|
||||
@@ -46,6 +48,8 @@ struct RoomDetailsScreenViewState: BindableState {
|
||||
var canEditRoomName = false
|
||||
var canEditRoomTopic = false
|
||||
var canEditRoomAvatar = false
|
||||
let showNotificationSettings: Bool
|
||||
var notificationSettingsState: RoomDetailsNotificationSettingsState = .loading
|
||||
|
||||
var canEdit: Bool {
|
||||
!isDirect && (canEditRoomName || canEditRoomTopic || canEditRoomAvatar)
|
||||
@@ -58,6 +62,36 @@ struct RoomDetailsScreenViewState: BindableState {
|
||||
var bindings: RoomDetailsScreenViewStateBindings
|
||||
|
||||
var dmRecipient: RoomMemberDetails?
|
||||
|
||||
var shortcuts: [RoomDetailsScreenViewShortcut] {
|
||||
var shortcuts: [RoomDetailsScreenViewShortcut] = []
|
||||
if showNotificationSettings {
|
||||
shortcuts.append(.mute)
|
||||
}
|
||||
if let permalink = dmRecipient?.permalink {
|
||||
shortcuts.append(.share(link: permalink))
|
||||
} else if let permalink {
|
||||
shortcuts.append(.share(link: permalink))
|
||||
}
|
||||
return shortcuts
|
||||
}
|
||||
|
||||
var isProcessingMuteToggleAction = false
|
||||
|
||||
var areNotificationsMuted: Bool {
|
||||
if case .loaded(let settings) = notificationSettingsState {
|
||||
return settings.mode == .mute
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var notificationShortcutButtonTitle: String {
|
||||
areNotificationsMuted ? L10n.commonUnmute : L10n.commonMute
|
||||
}
|
||||
|
||||
var notificationShortcutButtonImage: Image {
|
||||
areNotificationsMuted ? Image(systemName: "bell.slash.fill") : Image(systemName: "bell")
|
||||
}
|
||||
}
|
||||
|
||||
struct RoomDetailsScreenViewStateBindings {
|
||||
@@ -138,11 +172,64 @@ enum RoomDetailsScreenViewAction {
|
||||
case confirmLeave
|
||||
case ignoreConfirmed
|
||||
case unignoreConfirmed
|
||||
case processTapNotifications
|
||||
case processToogleMuteNotifications
|
||||
}
|
||||
|
||||
enum RoomDetailsScreenViewShortcut {
|
||||
case share(link: URL)
|
||||
case mute
|
||||
}
|
||||
|
||||
extension RoomDetailsScreenViewShortcut: Hashable { }
|
||||
|
||||
enum RoomDetailsNotificationSettingsState {
|
||||
case loading
|
||||
case loaded(settings: RoomNotificationSettingsProxyProtocol)
|
||||
case error
|
||||
}
|
||||
|
||||
extension RoomDetailsNotificationSettingsState {
|
||||
var label: String {
|
||||
switch self {
|
||||
case .loading:
|
||||
return L10n.commonLoading
|
||||
case .loaded(let settings):
|
||||
if settings.isDefault {
|
||||
return L10n.screenRoomDetailsNotificationModeDefault
|
||||
} else {
|
||||
return L10n.screenRoomDetailsNotificationModeCustom
|
||||
}
|
||||
case .error:
|
||||
return L10n.commonError
|
||||
}
|
||||
}
|
||||
|
||||
var isLoading: Bool {
|
||||
if case .loading = self {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var isLoaded: Bool {
|
||||
if case .loaded = self {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var isError: Bool {
|
||||
if case .error = self {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
enum RoomDetailsScreenErrorType: Hashable {
|
||||
/// A specific error message shown in an alert.
|
||||
case alert(String)
|
||||
case alert
|
||||
/// Leaving room has failed..
|
||||
case unknown
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
private let accountUserID: String
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let notificationSettingsProxy: NotificationSettingsProxyProtocol
|
||||
|
||||
private var accountOwner: RoomMemberProxyProtocol? {
|
||||
didSet { updatePowerLevelPermissions() }
|
||||
@@ -35,10 +36,13 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
init(accountUserID: String,
|
||||
roomProxy: RoomProxyProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
notificationSettingsProxy: NotificationSettingsProxyProtocol,
|
||||
appSettings: AppSettings) {
|
||||
self.accountUserID = accountUserID
|
||||
self.roomProxy = roomProxy
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.notificationSettingsProxy = notificationSettingsProxy
|
||||
|
||||
super.init(initialViewState: .init(roomId: roomProxy.id,
|
||||
canonicalAlias: roomProxy.canonicalAlias,
|
||||
@@ -49,11 +53,16 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
topic: roomProxy.topic,
|
||||
avatarURL: roomProxy.avatarURL,
|
||||
joinedMembersCount: roomProxy.joinedMembersCount,
|
||||
showNotificationSettings: appSettings.notificationSettingsEnabled,
|
||||
notificationSettingsState: .loading,
|
||||
bindings: .init()),
|
||||
imageProvider: mediaProvider)
|
||||
|
||||
setupRoomSubscription()
|
||||
fetchMembers()
|
||||
|
||||
setupNotificationSettingsSubscription()
|
||||
fetchNotificationSettings()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -87,6 +96,14 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
Task { await ignore() }
|
||||
case .unignoreConfirmed:
|
||||
Task { await unignore() }
|
||||
case .processTapNotifications:
|
||||
if state.notificationSettingsState.isError {
|
||||
fetchNotificationSettings()
|
||||
} else {
|
||||
callback?(.requestNotificationSettingsPresentation)
|
||||
}
|
||||
case .processToogleMuteNotifications:
|
||||
Task { await toggleMuteNotifications() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +163,66 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
state.canEditRoomAvatar = accountOwner?.canSendStateEvent(type: .roomAvatar) ?? false
|
||||
}
|
||||
|
||||
private func setupNotificationSettingsSubscription() {
|
||||
notificationSettingsProxy.callbacks
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] callback in
|
||||
guard let self else { return }
|
||||
|
||||
switch callback {
|
||||
case .settingsDidChange:
|
||||
self.fetchNotificationSettings()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func fetchNotificationSettings() {
|
||||
Task {
|
||||
await fetchRoomNotificationSettings()
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchRoomNotificationSettings() async {
|
||||
do {
|
||||
let notificationMode = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
|
||||
isEncrypted: roomProxy.isEncrypted,
|
||||
activeMembersCount: UInt64(roomProxy.activeMembersCount))
|
||||
state.notificationSettingsState = .loaded(settings: notificationMode)
|
||||
} catch {
|
||||
state.notificationSettingsState = .error
|
||||
state.bindings.alertInfo = AlertInfo(id: .alert,
|
||||
title: L10n.commonError,
|
||||
message: L10n.screenRoomDetailsErrorLoadingNotificationSettings)
|
||||
}
|
||||
}
|
||||
|
||||
private func toggleMuteNotifications() async {
|
||||
guard case .loaded(let notificationMode) = state.notificationSettingsState else { return }
|
||||
state.isProcessingMuteToggleAction = true
|
||||
switch notificationMode.mode {
|
||||
case .mute:
|
||||
do {
|
||||
try await notificationSettingsProxy.unmuteRoom(roomId: roomProxy.id,
|
||||
isEncrypted: roomProxy.isEncrypted,
|
||||
activeMembersCount: UInt64(roomProxy.activeMembersCount))
|
||||
} catch {
|
||||
state.bindings.alertInfo = AlertInfo(id: .alert,
|
||||
title: L10n.commonError,
|
||||
message: L10n.screenRoomDetailsErrorUnmuting)
|
||||
}
|
||||
default:
|
||||
do {
|
||||
try await notificationSettingsProxy.setNotificationMode(roomId: roomProxy.id, mode: .mute)
|
||||
} catch {
|
||||
state.bindings.alertInfo = AlertInfo(id: .alert,
|
||||
title: L10n.commonError,
|
||||
message: L10n.screenRoomDetailsErrorMuting)
|
||||
}
|
||||
}
|
||||
state.isProcessingMuteToggleAction = false
|
||||
}
|
||||
|
||||
private static let leaveRoomLoadingID = "LeaveRoomLoading"
|
||||
|
||||
private func leaveRoom() async {
|
||||
|
||||
@@ -30,6 +30,10 @@ struct RoomDetailsScreen: View {
|
||||
}
|
||||
|
||||
topicSection
|
||||
|
||||
if context.viewState.showNotificationSettings {
|
||||
notificationSection
|
||||
}
|
||||
|
||||
if context.viewState.dmRecipient == nil {
|
||||
aboutSection
|
||||
@@ -73,14 +77,8 @@ struct RoomDetailsScreen: View {
|
||||
avatarSize: .room(on: .details),
|
||||
imageProvider: context.imageProvider,
|
||||
subtitle: context.viewState.canonicalAlias) {
|
||||
if let permalink = context.viewState.permalink {
|
||||
HStack(spacing: 32) {
|
||||
ShareLink(item: permalink) {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
}
|
||||
.buttonStyle(FormActionButtonStyle(title: L10n.actionShare))
|
||||
}
|
||||
.padding(.top, 32)
|
||||
if !context.viewState.shortcuts.isEmpty {
|
||||
headerSectionShortcuts
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomDetailsScreen.avatar)
|
||||
@@ -94,17 +92,29 @@ struct RoomDetailsScreen: View {
|
||||
avatarSize: .user(on: .memberDetails),
|
||||
imageProvider: context.imageProvider,
|
||||
subtitle: recipient.id) {
|
||||
if let permalink = recipient.permalink {
|
||||
HStack(spacing: 32) {
|
||||
if !context.viewState.shortcuts.isEmpty {
|
||||
headerSectionShortcuts
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomDetailsScreen.dmAvatar)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var headerSectionShortcuts: some View {
|
||||
HStack(spacing: 32) {
|
||||
ForEach(context.viewState.shortcuts, id: \.self) { shortcut in
|
||||
switch shortcut {
|
||||
case .mute:
|
||||
toggleMuteButton
|
||||
case .share(let permalink):
|
||||
ShareLink(item: permalink) {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
}
|
||||
.buttonStyle(FormActionButtonStyle(title: L10n.actionShare))
|
||||
}
|
||||
.padding(.top, 32)
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomDetailsScreen.dmAvatar)
|
||||
.padding(.top, 32)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@@ -163,6 +173,49 @@ struct RoomDetailsScreen: View {
|
||||
.compoundFormSection()
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var notificationSection: some View {
|
||||
Section {
|
||||
Button {
|
||||
context.send(viewAction: .processTapNotifications)
|
||||
} label: {
|
||||
LabeledContent {
|
||||
if context.viewState.notificationSettingsState.isLoading {
|
||||
ProgressView()
|
||||
} else if context.viewState.notificationSettingsState.isError {
|
||||
Image(systemName: "exclamationmark.circle")
|
||||
} else {
|
||||
Text(context.viewState.notificationSettingsState.label)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
.font(.compound.bodyLG)
|
||||
}
|
||||
} label: {
|
||||
Label(L10n.screenRoomDetailsNotificationTitle, systemImage: "bell")
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomDetailsScreen.notifications)
|
||||
}
|
||||
.listRowSeparatorTint(.compound.borderDisabled)
|
||||
.buttonStyle(FormButtonStyle(accessory: context.viewState.notificationSettingsState.isLoaded ? .navigationLink : nil))
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
.disabled(context.viewState.notificationSettingsState.isLoading)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var toggleMuteButton: some View {
|
||||
Button {
|
||||
context.send(viewAction: .processToogleMuteNotifications)
|
||||
} label: {
|
||||
if context.viewState.isProcessingMuteToggleAction {
|
||||
ProgressView()
|
||||
} else {
|
||||
context.viewState.notificationShortcutButtonImage
|
||||
}
|
||||
}
|
||||
.buttonStyle(FormActionButtonStyle(title: context.viewState.notificationShortcutButtonTitle))
|
||||
.disabled(context.viewState.isProcessingMuteToggleAction)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var securitySection: some View {
|
||||
@@ -256,10 +309,17 @@ struct RoomDetailsScreen_Previews: PreviewProvider {
|
||||
canonicalAlias: "#alias:domain.com",
|
||||
members: members))
|
||||
|
||||
var notificationSettingsProxyMockConfiguration = NotificationSettingsProxyMockConfiguration()
|
||||
notificationSettingsProxyMockConfiguration.roomMode.isDefault = false
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: notificationSettingsProxyMockConfiguration)
|
||||
let appSettings = AppSettings()
|
||||
|
||||
return RoomDetailsScreenViewModel(accountUserID: "@owner:somewhere.com",
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
appSettings: appSettings)
|
||||
}()
|
||||
|
||||
static let dmRoomViewModel = {
|
||||
@@ -274,11 +334,15 @@ struct RoomDetailsScreen_Previews: PreviewProvider {
|
||||
isEncrypted: true,
|
||||
canonicalAlias: "#alias:domain.com",
|
||||
members: members))
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
|
||||
let appSettings = AppSettings()
|
||||
|
||||
return RoomDetailsScreenViewModel(accountUserID: "@owner:somewhere.com",
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
appSettings: appSettings)
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
@@ -357,6 +357,13 @@ 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) {
|
||||
|
||||
@@ -113,4 +113,6 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
||||
func searchUsers(searchTerm: String, limit: UInt) async -> Result<SearchUsersResultsProxy, ClientProxyError>
|
||||
|
||||
func profile(for userID: String) async -> Result<UserProfileProxy, ClientProxyError>
|
||||
|
||||
func notificationSettings() async -> NotificationSettingsProxyProtocol
|
||||
}
|
||||
|
||||
@@ -140,4 +140,13 @@ class MockClientProxy: ClientProxyProtocol {
|
||||
getProfileCalled = true
|
||||
return getProfileResult
|
||||
}
|
||||
|
||||
var notificationSettingsResult: NotificationSettingsProxyProtocol?
|
||||
func notificationSettings() -> NotificationSettingsProxyProtocol {
|
||||
if let notificationSettingsResult {
|
||||
return notificationSettingsResult
|
||||
} else {
|
||||
return NotificationSettingsProxyMock(with: .init())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
private final class WeakNotificationSettingsProxy: NotificationSettingsDelegate {
|
||||
private weak var proxy: NotificationSettingsProxy?
|
||||
|
||||
init(proxy: NotificationSettingsProxy) {
|
||||
self.proxy = proxy
|
||||
}
|
||||
|
||||
// MARK: - NotificationSettingsDelegate
|
||||
|
||||
func settingsDidChange() {
|
||||
Task {
|
||||
await proxy?.settingsDidChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
private(set) var notificationSettings: MatrixRustSDK.NotificationSettingsProtocol
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol?
|
||||
|
||||
let callbacks = PassthroughSubject<NotificationSettingsProxyCallback, Never>()
|
||||
|
||||
init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol, backgroundTaskService: BackgroundTaskServiceProtocol?) {
|
||||
self.notificationSettings = notificationSettings
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
notificationSettings.setDelegate(delegate: WeakNotificationSettingsProxy(proxy: self))
|
||||
}
|
||||
|
||||
func getNotificationSettings(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64) async throws -> RoomNotificationSettingsProxyProtocol {
|
||||
let roomMotificationSettings = try await notificationSettings.getRoomNotificationSettings(roomId: roomId, isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
return RoomNotificationSettingsProxy(roomNotificationSettings: roomMotificationSettings)
|
||||
}
|
||||
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationMode) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setRoomNotificationMode(roomId: roomId, mode: mode)
|
||||
}
|
||||
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationMode {
|
||||
await notificationSettings.getDefaultRoomNotificationMode(isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
}
|
||||
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "restoreDefaultNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.restoreDefaultRoomNotificationMode(roomId: roomId)
|
||||
}
|
||||
|
||||
func containsKeywordsRules() async -> Bool {
|
||||
await notificationSettings.containsKeywordsRules()
|
||||
}
|
||||
|
||||
func unmuteRoom(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "unmuteRoom")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.unmuteRoom(roomId: roomId, isEncrypted: isEncrypted, membersCount: activeMembersCount)
|
||||
}
|
||||
|
||||
func isRoomMentionEnabled() async throws -> Bool {
|
||||
try await notificationSettings.isRoomMentionEnabled()
|
||||
}
|
||||
|
||||
func setRoomMentionEnabled(enabled: Bool) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setRoomMentionEnabled")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setRoomMentionEnabled(enabled: enabled)
|
||||
}
|
||||
|
||||
func isUserMentionEnabled() async throws -> Bool {
|
||||
try await notificationSettings.isUserMentionEnabled()
|
||||
}
|
||||
|
||||
func setUserMentionEnabled(enabled: Bool) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setUserMentionEnabled")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setUserMentionEnabled(enabled: enabled)
|
||||
}
|
||||
|
||||
func isCallEnabled() async throws -> Bool {
|
||||
try await notificationSettings.isCallEnabled()
|
||||
}
|
||||
|
||||
func setCallEnabled(enabled: Bool) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setCallEnabled")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setCallEnabled(enabled: enabled)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@MainActor
|
||||
func settingsDidChange() {
|
||||
callbacks.send(.settingsDidChange)
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
enum NotificationSettingsProxyCallback {
|
||||
case settingsDidChange
|
||||
}
|
||||
|
||||
// sourcery: AutoMockable
|
||||
protocol NotificationSettingsProxyProtocol {
|
||||
var callbacks: PassthroughSubject<NotificationSettingsProxyCallback, Never> { get }
|
||||
|
||||
func getNotificationSettings(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64) async throws -> RoomNotificationSettingsProxyProtocol
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationMode) async throws
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationMode
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws
|
||||
func containsKeywordsRules() async -> Bool
|
||||
func unmuteRoom(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64) async throws
|
||||
func isRoomMentionEnabled() async throws -> Bool
|
||||
func setRoomMentionEnabled(enabled: Bool) async throws
|
||||
func isUserMentionEnabled() async throws -> Bool
|
||||
func setUserMentionEnabled(enabled: Bool) async throws
|
||||
func isCallEnabled() async throws -> Bool
|
||||
func setCallEnabled(enabled: Bool) async throws
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
struct RoomNotificationSettingsProxy: RoomNotificationSettingsProxyProtocol {
|
||||
private let roomNotificationSettings: RoomNotificationSettings
|
||||
|
||||
var mode: RoomNotificationMode {
|
||||
roomNotificationSettings.mode
|
||||
}
|
||||
|
||||
var isDefault: Bool {
|
||||
roomNotificationSettings.isDefault
|
||||
}
|
||||
|
||||
init(roomNotificationSettings: RoomNotificationSettings) {
|
||||
self.roomNotificationSettings = roomNotificationSettings
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
// sourcery: AutoMockable
|
||||
protocol RoomNotificationSettingsProxyProtocol {
|
||||
var mode: RoomNotificationMode { get }
|
||||
var isDefault: Bool { get }
|
||||
}
|
||||
@@ -360,7 +360,8 @@ class MockScreen: Identifiable {
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
userDiscoveryService: UserDiscoveryServiceMock(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init())))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenWithRoomAvatar:
|
||||
@@ -380,7 +381,8 @@ class MockScreen: Identifiable {
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
userDiscoveryService: UserDiscoveryServiceMock(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init())))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenWithEmptyTopic:
|
||||
@@ -402,7 +404,8 @@ class MockScreen: Identifiable {
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
userDiscoveryService: UserDiscoveryServiceMock(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init())))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenWithInvite:
|
||||
@@ -420,7 +423,8 @@ class MockScreen: Identifiable {
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
userDiscoveryService: UserDiscoveryServiceMock(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init())))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenDmDetails:
|
||||
@@ -439,7 +443,8 @@ class MockScreen: Identifiable {
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
userDiscoveryService: UserDiscoveryServiceMock(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init())))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomEditDetails, .roomEditDetailsReadOnly:
|
||||
|
||||
Reference in New Issue
Block a user