mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Edit the room Notification setting (#1394)
This commit is contained in:
@@ -352,11 +352,11 @@ class NotificationSettingsProxyMock: NotificationSettingsProxyProtocol {
|
||||
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)?
|
||||
var setNotificationModeRoomIdModeReceivedArguments: (roomId: String, mode: RoomNotificationModeProxy)?
|
||||
var setNotificationModeRoomIdModeReceivedInvocations: [(roomId: String, mode: RoomNotificationModeProxy)] = []
|
||||
var setNotificationModeRoomIdModeClosure: ((String, RoomNotificationModeProxy) async throws -> Void)?
|
||||
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationMode) async throws {
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationModeProxy) async throws {
|
||||
if let error = setNotificationModeRoomIdModeThrowableError {
|
||||
throw error
|
||||
}
|
||||
@@ -373,10 +373,10 @@ class NotificationSettingsProxyMock: NotificationSettingsProxyProtocol {
|
||||
}
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedArguments: (isEncrypted: Bool, activeMembersCount: UInt64)?
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedInvocations: [(isEncrypted: Bool, activeMembersCount: UInt64)] = []
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReturnValue: RoomNotificationMode!
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountClosure: ((Bool, UInt64) async -> RoomNotificationMode)?
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReturnValue: RoomNotificationModeProxy!
|
||||
var getDefaultNotificationRoomModeIsEncryptedActiveMembersCountClosure: ((Bool, UInt64) async -> RoomNotificationModeProxy)?
|
||||
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationMode {
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationModeProxy {
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountCallsCount += 1
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedArguments = (isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReceivedInvocations.append((isEncrypted: isEncrypted, activeMembersCount: activeMembersCount))
|
||||
@@ -668,11 +668,11 @@ class RoomMemberProxyMock: RoomMemberProxyProtocol {
|
||||
}
|
||||
}
|
||||
class RoomNotificationSettingsProxyMock: RoomNotificationSettingsProxyProtocol {
|
||||
var mode: RoomNotificationMode {
|
||||
var mode: RoomNotificationModeProxy {
|
||||
get { return underlyingMode }
|
||||
set(value) { underlyingMode = value }
|
||||
}
|
||||
var underlyingMode: RoomNotificationMode!
|
||||
var underlyingMode: RoomNotificationModeProxy!
|
||||
var isDefault: Bool {
|
||||
get { return underlyingIsDefault }
|
||||
set(value) { underlyingIsDefault = value }
|
||||
|
||||
@@ -20,8 +20,13 @@ import MatrixRustSDK
|
||||
|
||||
struct NotificationSettingsProxyMockConfiguration {
|
||||
var callback = PassthroughSubject<NotificationSettingsProxyCallback, Never>()
|
||||
var defaultRoomMode: RoomNotificationMode = .mentionsAndKeywordsOnly
|
||||
var roomMode = RoomNotificationSettingsProxyMock(with: RoomNotificationSettingsProxyMockConfiguration(mode: .allMessages, isDefault: true))
|
||||
var defaultRoomMode: RoomNotificationModeProxy
|
||||
var roomMode: RoomNotificationSettingsProxyMock
|
||||
|
||||
init(defaultRoomMode: RoomNotificationModeProxy = .allMessages, roomMode: RoomNotificationModeProxy = .allMessages) {
|
||||
self.defaultRoomMode = defaultRoomMode
|
||||
self.roomMode = RoomNotificationSettingsProxyMock(with: RoomNotificationSettingsProxyMockConfiguration(mode: roomMode, isDefault: defaultRoomMode == roomMode))
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationSettingsProxyMock {
|
||||
@@ -31,5 +36,20 @@ extension NotificationSettingsProxyMock {
|
||||
callbacks = configuration.callback
|
||||
getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReturnValue = configuration.roomMode
|
||||
getDefaultNotificationRoomModeIsEncryptedActiveMembersCountReturnValue = configuration.defaultRoomMode
|
||||
|
||||
setNotificationModeRoomIdModeClosure = { [weak self] _, mode in
|
||||
guard let self else { return }
|
||||
self.getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReturnValue = RoomNotificationSettingsProxyMock(with: .init(mode: mode, isDefault: false))
|
||||
Task {
|
||||
self.callbacks.send(.settingsDidChange)
|
||||
}
|
||||
}
|
||||
restoreDefaultNotificationModeRoomIdClosure = { [weak self] _ in
|
||||
guard let self else { return }
|
||||
self.getNotificationSettingsRoomIdIsEncryptedActiveMembersCountReturnValue = RoomNotificationSettingsProxyMock(with: .init(mode: configuration.defaultRoomMode, isDefault: true))
|
||||
Task {
|
||||
self.callbacks.send(.settingsDidChange)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
struct RoomNotificationSettingsProxyMockConfiguration {
|
||||
var mode: RoomNotificationMode = .allMessages
|
||||
var mode: RoomNotificationModeProxy = .allMessages
|
||||
var isDefault = true
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ struct A11yIdentifiers {
|
||||
static let reportContent = ReportContent()
|
||||
static let roomScreen = RoomScreen()
|
||||
static let roomDetailsScreen = RoomDetailsScreen()
|
||||
static let roomNotificationSettingsScreen = RoomNotificationSettingsScreen()
|
||||
static let serverConfirmationScreen = ServerConfirmationScreen()
|
||||
static let sessionVerificationScreen = SessionVerificationScreen()
|
||||
static let softLogoutScreen = SoftLogoutScreen()
|
||||
@@ -111,6 +112,10 @@ struct A11yIdentifiers {
|
||||
let unignore = "room_member_details-unignore"
|
||||
}
|
||||
|
||||
struct RoomNotificationSettingsScreen {
|
||||
let allowCustomSetting = "room_notification_settings-allow_custom"
|
||||
}
|
||||
|
||||
struct ServerConfirmationScreen {
|
||||
let `continue` = "server_confirmation-continue"
|
||||
let changeServer = "server_confirmation-change_server"
|
||||
|
||||
@@ -188,7 +188,12 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func presentNotificationSettings() { }
|
||||
private func presentNotificationSettings() {
|
||||
let roomNotificationSettingsParameters = RoomNotificationSettingsScreenCoordinatorParameters(notificationSettingsProxy: parameters.notificationSettings,
|
||||
roomProxy: parameters.roomProxy)
|
||||
let roomNotificationSettingsCoordinator = RoomNotificationSettingsScreenCoordinator(parameters: roomNotificationSettingsParameters)
|
||||
navigationStackCoordinator?.push(roomNotificationSettingsCoordinator)
|
||||
}
|
||||
}
|
||||
|
||||
private extension Result {
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright 2022 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 SwiftUI
|
||||
|
||||
struct RoomNotificationSettingsScreenCoordinatorParameters {
|
||||
let notificationSettingsProxy: NotificationSettingsProxyProtocol
|
||||
let roomProxy: RoomProxyProtocol
|
||||
}
|
||||
|
||||
final class RoomNotificationSettingsScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: RoomNotificationSettingsScreenCoordinatorParameters
|
||||
private var viewModel: RoomNotificationSettingsScreenViewModelProtocol
|
||||
|
||||
init(parameters: RoomNotificationSettingsScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
viewModel = RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: parameters.notificationSettingsProxy,
|
||||
roomProxy: parameters.roomProxy)
|
||||
}
|
||||
|
||||
func start() { }
|
||||
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(RoomNotificationSettingsScreen(context: viewModel.context))
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// Copyright 2022 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
|
||||
|
||||
enum RoomNotificationSettingsScreenViewModelAction { }
|
||||
|
||||
enum RoomNotificationSettingsState {
|
||||
case loading
|
||||
case loaded(settings: RoomNotificationSettingsProxyProtocol)
|
||||
case error
|
||||
}
|
||||
|
||||
extension RoomNotificationSettingsState {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
struct RoomNotificationSettingsScreenViewState: BindableState {
|
||||
var bindings: RoomNotificationSettingsScreenViewStateBindings
|
||||
let strings = RoomNotificationSettingsScreenStrings()
|
||||
var notificationSettingsState: RoomNotificationSettingsState = .loading
|
||||
var availableCustomRoomNotificationModes: [RoomNotificationModeProxy] = [.allMessages, .mentionsAndKeywordsOnly, .mute]
|
||||
var isRestoringDefautSetting = false
|
||||
var pendingCustomMode: RoomNotificationModeProxy?
|
||||
}
|
||||
|
||||
struct RoomNotificationSettingsScreenViewStateBindings {
|
||||
var allowCustomSetting = false
|
||||
var customMode: RoomNotificationModeProxy = .allMessages
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<RoomNotificationSettingsScreenErrorType>?
|
||||
}
|
||||
|
||||
enum RoomNotificationSettingsScreenViewAction {
|
||||
case changedAllowCustomSettings
|
||||
case setCustomMode(RoomNotificationModeProxy)
|
||||
}
|
||||
|
||||
struct RoomNotificationSettingsScreenStrings {
|
||||
let customSettingFootnote: AttributedString
|
||||
|
||||
init() {
|
||||
let linkPlaceholder = "{link}"
|
||||
var customSettingFootnote = AttributedString(L10n.screenRoomNotificationSettingsDefaultSettingFootnote(linkPlaceholder))
|
||||
var linkString = AttributedString(L10n.screenRoomNotificationSettingsDefaultSettingFootnoteContentLink)
|
||||
linkString.bold()
|
||||
customSettingFootnote.replace(linkPlaceholder, with: linkString)
|
||||
|
||||
self.customSettingFootnote = customSettingFootnote
|
||||
}
|
||||
|
||||
func string(for mode: RoomNotificationModeProxy) -> String {
|
||||
switch mode {
|
||||
case .allMessages:
|
||||
return L10n.screenRoomNotificationSettingsModeAllMessages
|
||||
case .mentionsAndKeywordsOnly:
|
||||
return L10n.screenRoomNotificationSettingsModeMentionsAndKeywords
|
||||
case .mute:
|
||||
return L10n.commonMute
|
||||
}
|
||||
}
|
||||
|
||||
func string(for state: RoomNotificationSettingsState) -> String {
|
||||
switch state {
|
||||
case .loading:
|
||||
return L10n.commonLoading
|
||||
case .loaded(let settings):
|
||||
return string(for: settings.mode)
|
||||
case .error:
|
||||
return L10n.commonError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum RoomNotificationSettingsScreenErrorType: Hashable {
|
||||
case loadingSettingsFailed
|
||||
case setModeFailed
|
||||
case restoreDefaultFailed
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// Copyright 2022 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 SwiftUI
|
||||
|
||||
typealias RoomNotificationSettingsScreenViewModelType = StateStoreViewModel<RoomNotificationSettingsScreenViewState, RoomNotificationSettingsScreenViewAction>
|
||||
|
||||
class RoomNotificationSettingsScreenViewModel: RoomNotificationSettingsScreenViewModelType, RoomNotificationSettingsScreenViewModelProtocol {
|
||||
private let actionsSubject: PassthroughSubject<RoomNotificationSettingsScreenViewModelAction, Never> = .init()
|
||||
private let notificationSettingsProxy: NotificationSettingsProxyProtocol
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
|
||||
@CancellableTask private var fetchNotificationSettingsTask: Task<Void, Error>?
|
||||
|
||||
var actions: AnyPublisher<RoomNotificationSettingsScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(notificationSettingsProxy: NotificationSettingsProxyProtocol, roomProxy: RoomProxyProtocol) {
|
||||
let bindings = RoomNotificationSettingsScreenViewStateBindings()
|
||||
self.notificationSettingsProxy = notificationSettingsProxy
|
||||
self.roomProxy = roomProxy
|
||||
super.init(initialViewState: RoomNotificationSettingsScreenViewState(bindings: bindings))
|
||||
|
||||
setupNotificationSettingsSubscription()
|
||||
fetchNotificationSettings()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: RoomNotificationSettingsScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .changedAllowCustomSettings:
|
||||
toogleCustomSetting()
|
||||
case .setCustomMode(let mode):
|
||||
setCustomMode(mode)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
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() {
|
||||
fetchNotificationSettingsTask = Task {
|
||||
await fetchRoomNotificationSettings()
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchRoomNotificationSettings() async {
|
||||
do {
|
||||
let settings = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
|
||||
isEncrypted: roomProxy.isEncrypted,
|
||||
activeMembersCount: UInt64(roomProxy.activeMembersCount))
|
||||
guard !Task.isCancelled else { return }
|
||||
state.notificationSettingsState = .loaded(settings: settings)
|
||||
if !state.isRestoringDefautSetting {
|
||||
state.bindings.allowCustomSetting = !settings.isDefault
|
||||
}
|
||||
if state.pendingCustomMode == nil {
|
||||
state.bindings.customMode = settings.mode
|
||||
}
|
||||
} catch {
|
||||
state.notificationSettingsState = .error
|
||||
displayError(.loadingSettingsFailed)
|
||||
}
|
||||
}
|
||||
|
||||
private func toogleCustomSetting() {
|
||||
guard case .loaded(let settings) = state.notificationSettingsState else { return }
|
||||
guard state.bindings.allowCustomSetting == settings.isDefault else { return }
|
||||
|
||||
if state.bindings.allowCustomSetting {
|
||||
setCustomMode(settings.mode)
|
||||
} else {
|
||||
restoreDefaultSetting()
|
||||
}
|
||||
}
|
||||
|
||||
private func restoreDefaultSetting() {
|
||||
state.isRestoringDefautSetting = true
|
||||
Task {
|
||||
do {
|
||||
try await notificationSettingsProxy.restoreDefaultNotificationMode(roomId: roomProxy.id)
|
||||
} catch {
|
||||
displayError(.restoreDefaultFailed)
|
||||
}
|
||||
state.isRestoringDefautSetting = false
|
||||
}
|
||||
}
|
||||
|
||||
private func setCustomMode(_ mode: RoomNotificationModeProxy) {
|
||||
// Check if the new mode is already the current one
|
||||
if case .loaded(let currentSettings) = state.notificationSettingsState {
|
||||
if !currentSettings.isDefault, currentSettings.mode == mode {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
state.pendingCustomMode = mode
|
||||
Task {
|
||||
do {
|
||||
try await notificationSettingsProxy.setNotificationMode(roomId: roomProxy.id, mode: mode)
|
||||
} catch {
|
||||
displayError(.setModeFailed)
|
||||
}
|
||||
state.pendingCustomMode = nil
|
||||
}
|
||||
}
|
||||
|
||||
private func displayError(_ type: RoomNotificationSettingsScreenErrorType) {
|
||||
switch type {
|
||||
case .loadingSettingsFailed:
|
||||
state.bindings.alertInfo = AlertInfo(id: type,
|
||||
title: L10n.commonError,
|
||||
message: L10n.screenRoomNotificationSettingsErrorLoadingSettings)
|
||||
case .setModeFailed:
|
||||
state.bindings.alertInfo = AlertInfo(id: type,
|
||||
title: L10n.commonError,
|
||||
message: L10n.screenRoomNotificationSettingsErrorSettingMode)
|
||||
|
||||
case .restoreDefaultFailed:
|
||||
state.bindings.alertInfo = AlertInfo(id: type,
|
||||
title: L10n.commonError,
|
||||
message: L10n.screenRoomNotificationSettingsErrorRestoringDefault)
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright 2022 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
|
||||
|
||||
@MainActor
|
||||
protocol RoomNotificationSettingsScreenViewModelProtocol {
|
||||
var actions: AnyPublisher<RoomNotificationSettingsScreenViewModelAction, Never> { get }
|
||||
var context: RoomNotificationSettingsScreenViewModelType.Context { get }
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Copyright 2022 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 SwiftUI
|
||||
|
||||
struct RoomNotificationSettingsScreen: View {
|
||||
@ObservedObject var context: RoomNotificationSettingsScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
allowCustomSettingSection
|
||||
|
||||
if !context.allowCustomSetting {
|
||||
defaultSettingSection
|
||||
} else {
|
||||
customSettingsSection
|
||||
}
|
||||
}
|
||||
.compoundForm()
|
||||
.navigationTitle(L10n.screenRoomDetailsNotificationTitle)
|
||||
.alert(item: $context.alertInfo)
|
||||
.track(screen: .roomNotifications)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@ViewBuilder
|
||||
private var allowCustomSettingSection: some View {
|
||||
Section {
|
||||
Toggle(isOn: $context.allowCustomSetting) {
|
||||
Text(L10n.screenRoomNotificationSettingsAllowCustom)
|
||||
}
|
||||
.toggleStyle(.compoundForm)
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomNotificationSettingsScreen.allowCustomSetting)
|
||||
.disabled(context.viewState.notificationSettingsState.isLoading)
|
||||
.onChange(of: context.allowCustomSetting) { _ in
|
||||
context.send(viewAction: .changedAllowCustomSettings)
|
||||
}
|
||||
} footer: {
|
||||
Text(L10n.screenRoomNotificationSettingsAllowCustomFootnote)
|
||||
.compoundFormSectionFooter()
|
||||
}
|
||||
.compoundFormSection()
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var defaultSettingSection: some View {
|
||||
Section {
|
||||
if context.viewState.isRestoringDefautSetting {
|
||||
Text(L10n.commonLoading)
|
||||
.foregroundColor(.compound.textPlaceholder)
|
||||
} else {
|
||||
Text(context.viewState.strings.string(for: context.viewState.notificationSettingsState))
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
}
|
||||
} header: {
|
||||
Text(L10n.screenRoomNotificationSettingsDefaultSettingTitle)
|
||||
.compoundFormSectionHeader()
|
||||
} footer: {
|
||||
Text(context.viewState.strings.customSettingFootnote)
|
||||
.compoundFormSectionFooter()
|
||||
}
|
||||
.compoundFormSection()
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var customSettingsSection: some View {
|
||||
Section {
|
||||
Picker("", selection: $context.customMode) {
|
||||
ForEach(context.viewState.availableCustomRoomNotificationModes, id: \.self) { mode in
|
||||
Text(context.viewState.strings.string(for: mode))
|
||||
.tag(mode)
|
||||
}
|
||||
}
|
||||
.onChange(of: context.customMode) { mode in
|
||||
context.send(viewAction: .setCustomMode(mode))
|
||||
}
|
||||
.labelsHidden()
|
||||
.pickerStyle(.inline)
|
||||
} header: {
|
||||
Text(L10n.screenRoomNotificationSettingsCustomSettingsTitle)
|
||||
.compoundFormSectionHeader()
|
||||
}
|
||||
.compoundFormSection()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct RoomNotificationSettingsScreen_Previews: PreviewProvider {
|
||||
static let viewModel = {
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .mentionsAndKeywordsOnly, roomMode: .mentionsAndKeywordsOnly))
|
||||
|
||||
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: true, joinedMembersCount: 4))
|
||||
|
||||
let model = RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
|
||||
roomProxy: roomProxy)
|
||||
|
||||
return model
|
||||
}()
|
||||
|
||||
static let viewModelCustom = {
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly))
|
||||
|
||||
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: true, joinedMembersCount: 4))
|
||||
|
||||
let model = RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
|
||||
roomProxy: roomProxy)
|
||||
|
||||
return model
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
RoomNotificationSettingsScreen(context: viewModel.context)
|
||||
.previewDisplayName("Default")
|
||||
RoomNotificationSettingsScreen(context: viewModelCustom.context)
|
||||
.previewDisplayName("Custom")
|
||||
}
|
||||
}
|
||||
@@ -51,15 +51,26 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
return RoomNotificationSettingsProxy(roomNotificationSettings: roomMotificationSettings)
|
||||
}
|
||||
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationMode) async throws {
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationModeProxy) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setRoomNotificationMode(roomId: roomId, mode: mode)
|
||||
let roomNotificationMode: RoomNotificationMode
|
||||
switch mode {
|
||||
case .allMessages:
|
||||
roomNotificationMode = .allMessages
|
||||
case .mentionsAndKeywordsOnly:
|
||||
roomNotificationMode = .mentionsAndKeywordsOnly
|
||||
case .mute:
|
||||
roomNotificationMode = .mute
|
||||
}
|
||||
try await notificationSettings.setRoomNotificationMode(roomId: roomId, mode: roomNotificationMode)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationMode {
|
||||
await notificationSettings.getDefaultRoomNotificationMode(isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationModeProxy {
|
||||
let roomNotificationMode = await notificationSettings.getDefaultRoomNotificationMode(isEncrypted: isEncrypted, activeMembersCount: activeMembersCount)
|
||||
return RoomNotificationModeProxy.from(roomNotificationMode: roomNotificationMode)
|
||||
}
|
||||
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws {
|
||||
@@ -67,6 +78,7 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.restoreDefaultRoomNotificationMode(roomId: roomId)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func containsKeywordsRules() async -> Bool {
|
||||
@@ -78,6 +90,7 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.unmuteRoom(roomId: roomId, isEncrypted: isEncrypted, membersCount: activeMembersCount)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func isRoomMentionEnabled() async throws -> Bool {
|
||||
@@ -89,6 +102,7 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setRoomMentionEnabled(enabled: enabled)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func isUserMentionEnabled() async throws -> Bool {
|
||||
@@ -100,6 +114,7 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setUserMentionEnabled(enabled: enabled)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func isCallEnabled() async throws -> Bool {
|
||||
@@ -111,10 +126,15 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setCallEnabled(enabled: enabled)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
func updatedSettings() async {
|
||||
_ = await callbacks.values.first(where: { $0 == .settingsDidChange })
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func settingsDidChange() {
|
||||
callbacks.send(.settingsDidChange)
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ 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 setNotificationMode(roomId: String, mode: RoomNotificationModeProxy) async throws
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, activeMembersCount: UInt64) async -> RoomNotificationModeProxy
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws
|
||||
func containsKeywordsRules() async -> Bool
|
||||
func unmuteRoom(roomId: String, isEncrypted: Bool, activeMembersCount: UInt64) async throws
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
enum RoomNotificationModeProxy {
|
||||
case allMessages
|
||||
case mentionsAndKeywordsOnly
|
||||
case mute
|
||||
}
|
||||
|
||||
extension RoomNotificationModeProxy {
|
||||
static func from(roomNotificationMode: RoomNotificationMode) -> Self {
|
||||
switch roomNotificationMode {
|
||||
case .allMessages:
|
||||
return .allMessages
|
||||
case .mentionsAndKeywordsOnly:
|
||||
return .mentionsAndKeywordsOnly
|
||||
case .mute:
|
||||
return .mute
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,8 @@ import MatrixRustSDK
|
||||
struct RoomNotificationSettingsProxy: RoomNotificationSettingsProxyProtocol {
|
||||
private let roomNotificationSettings: RoomNotificationSettings
|
||||
|
||||
var mode: RoomNotificationMode {
|
||||
roomNotificationSettings.mode
|
||||
var mode: RoomNotificationModeProxy {
|
||||
RoomNotificationModeProxy.from(roomNotificationMode: roomNotificationSettings.mode)
|
||||
}
|
||||
|
||||
var isDefault: Bool {
|
||||
|
||||
+1
-1
@@ -19,6 +19,6 @@ import MatrixRustSDK
|
||||
|
||||
// sourcery: AutoMockable
|
||||
protocol RoomNotificationSettingsProxyProtocol {
|
||||
var mode: RoomNotificationMode { get }
|
||||
var mode: RoomNotificationModeProxy { get }
|
||||
var isDefault: Bool { get }
|
||||
}
|
||||
|
||||
@@ -478,6 +478,20 @@ class MockScreen: Identifiable {
|
||||
roomProxy: RoomProxyMock(with: .init(displayName: "test", members: members))))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomNotificationSettingsDefaultSetting:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let members: [RoomMemberProxyMock] = [.mockInvitedAlice, .mockBob, .mockCharlie]
|
||||
let coordinator = RoomNotificationSettingsScreenCoordinator(parameters: .init(notificationSettingsProxy: NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .allMessages)),
|
||||
roomProxy: RoomProxyMock(with: .init(displayName: "test", members: members))))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomNotificationSettingsCustomSetting:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let members: [RoomMemberProxyMock] = [.mockInvitedAlice, .mockBob, .mockCharlie]
|
||||
let coordinator = RoomNotificationSettingsScreenCoordinator(parameters: .init(notificationSettingsProxy: NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly)),
|
||||
roomProxy: RoomProxyMock(with: .init(displayName: "test", members: members))))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .reportContent:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let coordinator = ReportContentScreenCoordinator(parameters: .init(eventID: "test",
|
||||
|
||||
@@ -60,6 +60,8 @@ enum UITestsScreenIdentifier: String {
|
||||
case roomMemberDetailsAccountOwner
|
||||
case roomMemberDetails
|
||||
case roomMemberDetailsIgnoredUser
|
||||
case roomNotificationSettingsDefaultSetting
|
||||
case roomNotificationSettingsCustomSetting
|
||||
case reportContent
|
||||
case startChat
|
||||
case startChatWithSearchResults
|
||||
|
||||
Reference in New Issue
Block a user