Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RoomChangePermissionsScreen #2513

Merged
merged 2 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions ElementX.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
"common_room" = "Room";
"common_room_name" = "Room name";
"common_room_name_placeholder" = "e.g. your project name";
"common_saving" = "Saving";
"common_screen_lock" = "Screen lock";
"common_search_for_someone" = "Search for someone";
"common_search_results" = "Search results";
Expand Down
2 changes: 2 additions & 0 deletions ElementX/Sources/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ internal enum L10n {
internal static var commonRoomName: String { return L10n.tr("Localizable", "common_room_name") }
/// e.g. your project name
internal static var commonRoomNamePlaceholder: String { return L10n.tr("Localizable", "common_room_name_placeholder") }
/// Saving
internal static var commonSaving: String { return L10n.tr("Localizable", "common_saving") }
/// Screen lock
internal static var commonScreenLock: String { return L10n.tr("Localizable", "common_screen_lock") }
/// Search for someone
Expand Down
164 changes: 101 additions & 63 deletions ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2723,69 +2723,6 @@ class RoomProxyMock: RoomProxyProtocol {
return uploadAvatarMediaReturnValue
}
}
//MARK: - canUserRedactOther

var canUserRedactOtherUserIDCallsCount = 0
var canUserRedactOtherUserIDCalled: Bool {
return canUserRedactOtherUserIDCallsCount > 0
}
var canUserRedactOtherUserIDReceivedUserID: String?
var canUserRedactOtherUserIDReceivedInvocations: [String] = []
var canUserRedactOtherUserIDReturnValue: Result<Bool, RoomProxyError>!
var canUserRedactOtherUserIDClosure: ((String) async -> Result<Bool, RoomProxyError>)?

func canUserRedactOther(userID: String) async -> Result<Bool, RoomProxyError> {
canUserRedactOtherUserIDCallsCount += 1
canUserRedactOtherUserIDReceivedUserID = userID
canUserRedactOtherUserIDReceivedInvocations.append(userID)
if let canUserRedactOtherUserIDClosure = canUserRedactOtherUserIDClosure {
return await canUserRedactOtherUserIDClosure(userID)
} else {
return canUserRedactOtherUserIDReturnValue
}
}
//MARK: - canUserRedactOwn

var canUserRedactOwnUserIDCallsCount = 0
var canUserRedactOwnUserIDCalled: Bool {
return canUserRedactOwnUserIDCallsCount > 0
}
var canUserRedactOwnUserIDReceivedUserID: String?
var canUserRedactOwnUserIDReceivedInvocations: [String] = []
var canUserRedactOwnUserIDReturnValue: Result<Bool, RoomProxyError>!
var canUserRedactOwnUserIDClosure: ((String) async -> Result<Bool, RoomProxyError>)?

func canUserRedactOwn(userID: String) async -> Result<Bool, RoomProxyError> {
canUserRedactOwnUserIDCallsCount += 1
canUserRedactOwnUserIDReceivedUserID = userID
canUserRedactOwnUserIDReceivedInvocations.append(userID)
if let canUserRedactOwnUserIDClosure = canUserRedactOwnUserIDClosure {
return await canUserRedactOwnUserIDClosure(userID)
} else {
return canUserRedactOwnUserIDReturnValue
}
}
//MARK: - canUserTriggerRoomNotification

var canUserTriggerRoomNotificationUserIDCallsCount = 0
var canUserTriggerRoomNotificationUserIDCalled: Bool {
return canUserTriggerRoomNotificationUserIDCallsCount > 0
}
var canUserTriggerRoomNotificationUserIDReceivedUserID: String?
var canUserTriggerRoomNotificationUserIDReceivedInvocations: [String] = []
var canUserTriggerRoomNotificationUserIDReturnValue: Result<Bool, RoomProxyError>!
var canUserTriggerRoomNotificationUserIDClosure: ((String) async -> Result<Bool, RoomProxyError>)?

func canUserTriggerRoomNotification(userID: String) async -> Result<Bool, RoomProxyError> {
canUserTriggerRoomNotificationUserIDCallsCount += 1
canUserTriggerRoomNotificationUserIDReceivedUserID = userID
canUserTriggerRoomNotificationUserIDReceivedInvocations.append(userID)
if let canUserTriggerRoomNotificationUserIDClosure = canUserTriggerRoomNotificationUserIDClosure {
return await canUserTriggerRoomNotificationUserIDClosure(userID)
} else {
return canUserTriggerRoomNotificationUserIDReturnValue
}
}
//MARK: - markAsRead

var markAsReadReceiptTypeCallsCount = 0
Expand Down Expand Up @@ -2871,6 +2808,107 @@ class RoomProxyMock: RoomProxyProtocol {
return flagAsFavouriteReturnValue
}
}
//MARK: - currentPowerLevelChanges

var currentPowerLevelChangesCallsCount = 0
var currentPowerLevelChangesCalled: Bool {
return currentPowerLevelChangesCallsCount > 0
}
var currentPowerLevelChangesReturnValue: Result<RoomPowerLevelChanges, RoomProxyError>!
var currentPowerLevelChangesClosure: (() async -> Result<RoomPowerLevelChanges, RoomProxyError>)?

func currentPowerLevelChanges() async -> Result<RoomPowerLevelChanges, RoomProxyError> {
currentPowerLevelChangesCallsCount += 1
if let currentPowerLevelChangesClosure = currentPowerLevelChangesClosure {
return await currentPowerLevelChangesClosure()
} else {
return currentPowerLevelChangesReturnValue
}
}
//MARK: - applyPowerLevelChanges

var applyPowerLevelChangesCallsCount = 0
var applyPowerLevelChangesCalled: Bool {
return applyPowerLevelChangesCallsCount > 0
}
var applyPowerLevelChangesReceivedChanges: RoomPowerLevelChanges?
var applyPowerLevelChangesReceivedInvocations: [RoomPowerLevelChanges] = []
var applyPowerLevelChangesReturnValue: Result<Void, RoomProxyError>!
var applyPowerLevelChangesClosure: ((RoomPowerLevelChanges) async -> Result<Void, RoomProxyError>)?

func applyPowerLevelChanges(_ changes: RoomPowerLevelChanges) async -> Result<Void, RoomProxyError> {
applyPowerLevelChangesCallsCount += 1
applyPowerLevelChangesReceivedChanges = changes
applyPowerLevelChangesReceivedInvocations.append(changes)
if let applyPowerLevelChangesClosure = applyPowerLevelChangesClosure {
return await applyPowerLevelChangesClosure(changes)
} else {
return applyPowerLevelChangesReturnValue
}
}
//MARK: - canUserRedactOther

var canUserRedactOtherUserIDCallsCount = 0
var canUserRedactOtherUserIDCalled: Bool {
return canUserRedactOtherUserIDCallsCount > 0
}
var canUserRedactOtherUserIDReceivedUserID: String?
var canUserRedactOtherUserIDReceivedInvocations: [String] = []
var canUserRedactOtherUserIDReturnValue: Result<Bool, RoomProxyError>!
var canUserRedactOtherUserIDClosure: ((String) async -> Result<Bool, RoomProxyError>)?

func canUserRedactOther(userID: String) async -> Result<Bool, RoomProxyError> {
canUserRedactOtherUserIDCallsCount += 1
canUserRedactOtherUserIDReceivedUserID = userID
canUserRedactOtherUserIDReceivedInvocations.append(userID)
if let canUserRedactOtherUserIDClosure = canUserRedactOtherUserIDClosure {
return await canUserRedactOtherUserIDClosure(userID)
} else {
return canUserRedactOtherUserIDReturnValue
}
}
//MARK: - canUserRedactOwn

var canUserRedactOwnUserIDCallsCount = 0
var canUserRedactOwnUserIDCalled: Bool {
return canUserRedactOwnUserIDCallsCount > 0
}
var canUserRedactOwnUserIDReceivedUserID: String?
var canUserRedactOwnUserIDReceivedInvocations: [String] = []
var canUserRedactOwnUserIDReturnValue: Result<Bool, RoomProxyError>!
var canUserRedactOwnUserIDClosure: ((String) async -> Result<Bool, RoomProxyError>)?

func canUserRedactOwn(userID: String) async -> Result<Bool, RoomProxyError> {
canUserRedactOwnUserIDCallsCount += 1
canUserRedactOwnUserIDReceivedUserID = userID
canUserRedactOwnUserIDReceivedInvocations.append(userID)
if let canUserRedactOwnUserIDClosure = canUserRedactOwnUserIDClosure {
return await canUserRedactOwnUserIDClosure(userID)
} else {
return canUserRedactOwnUserIDReturnValue
}
}
//MARK: - canUserTriggerRoomNotification

var canUserTriggerRoomNotificationUserIDCallsCount = 0
var canUserTriggerRoomNotificationUserIDCalled: Bool {
return canUserTriggerRoomNotificationUserIDCallsCount > 0
}
var canUserTriggerRoomNotificationUserIDReceivedUserID: String?
var canUserTriggerRoomNotificationUserIDReceivedInvocations: [String] = []
var canUserTriggerRoomNotificationUserIDReturnValue: Result<Bool, RoomProxyError>!
var canUserTriggerRoomNotificationUserIDClosure: ((String) async -> Result<Bool, RoomProxyError>)?

func canUserTriggerRoomNotification(userID: String) async -> Result<Bool, RoomProxyError> {
canUserTriggerRoomNotificationUserIDCallsCount += 1
canUserTriggerRoomNotificationUserIDReceivedUserID = userID
canUserTriggerRoomNotificationUserIDReceivedInvocations.append(userID)
if let canUserTriggerRoomNotificationUserIDClosure = canUserTriggerRoomNotificationUserIDClosure {
return await canUserTriggerRoomNotificationUserIDClosure(userID)
} else {
return canUserTriggerRoomNotificationUserIDReturnValue
}
}
//MARK: - kickUser

var kickUserCallsCount = 0
Expand Down
9 changes: 6 additions & 3 deletions ElementX/Sources/Mocks/RoomProxyMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,18 @@ extension RoomProxyMock {
setNameClosure = { _ in .success(()) }
setTopicClosure = { _ in .success(()) }
getMemberUserIDReturnValue = .success(configuration.memberForID)
canUserRedactOtherUserIDReturnValue = .success(false)
canUserTriggerRoomNotificationUserIDReturnValue = .success(configuration.canUserTriggerRoomNotification)
canUserJoinCallUserIDReturnValue = .success(configuration.canUserJoinCall)

flagAsUnreadReturnValue = .success(())
markAsReadReceiptTypeReturnValue = .success(())
underlyingIsFavourite = false
flagAsFavouriteReturnValue = .success(())

currentPowerLevelChangesReturnValue = .success(.init())
applyPowerLevelChangesReturnValue = .success(())
canUserRedactOtherUserIDReturnValue = .success(false)
canUserTriggerRoomNotificationUserIDReturnValue = .success(configuration.canUserTriggerRoomNotification)
canUserJoinCallUserIDReturnValue = .success(configuration.canUserJoinCall)

kickUserReturnValue = .success(())
banUserReturnValue = .success(())
unbanUserReturnValue = .success(())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// 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.
//

// periphery:ignore:all - this is just a roomChangePermissions remove this comment once generating the final file

import Combine
import SwiftUI

struct RoomChangePermissionsScreenCoordinatorParameters {
let permissions: RoomPermissions
let permissionsGroup: RoomRolesAndPermissionsScreenPermissionsGroup
let roomProxy: RoomProxyProtocol
let userIndicatorController: UserIndicatorControllerProtocol
}

enum RoomChangePermissionsScreenCoordinatorAction {
case cancel
}

final class RoomChangePermissionsScreenCoordinator: CoordinatorProtocol {
private let parameters: RoomChangePermissionsScreenCoordinatorParameters
private var viewModel: RoomChangePermissionsScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<RoomChangePermissionsScreenCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>()

var actions: AnyPublisher<RoomChangePermissionsScreenCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher()
}

init(parameters: RoomChangePermissionsScreenCoordinatorParameters) {
self.parameters = parameters

viewModel = RoomChangePermissionsScreenViewModel(currentPermissions: parameters.permissions,
group: parameters.permissionsGroup,
roomProxy: parameters.roomProxy,
userIndicatorController: parameters.userIndicatorController)
}

func start() {
viewModel.actions.sink { [weak self] action in
MXLog.info("Coordinator: received view model action: \(action)")

guard let self else { return }
switch action {
case .cancel:
actionsSubject.send(.cancel)
}
}
.store(in: &cancellables)
}

func toPresentable() -> AnyView {
AnyView(RoomChangePermissionsScreen(context: viewModel.context))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// 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
import MatrixRustSDK

enum RoomChangePermissionsScreenViewModelAction {
case cancel
}

struct RoomChangePermissionsScreenViewState: BindableState {
/// The screen's title.
let title: String
/// The current permissions that are set on the room.
var currentPermissions: RoomPermissions

var bindings: RoomChangePermissionsScreenViewStateBindings

/// Whether or not there are and changes to be saved.
var hasChanges: Bool {
bindings.settings.contains { currentPermissions[keyPath: $0.keyPath] ?? RoomPermissions.defaultValue(for: $0.keyPath) != $0.value }
}
}

struct RoomChangePermissionsScreenViewStateBindings: BindableState {
/// All of the settings shown for this screen.
var settings: [RoomPermissionsSetting]
/// Information about the currently displayed alert.
var alertInfo: AlertInfo<RoomChangePermissionsScreenAlertType>?
}

enum RoomChangePermissionsScreenAlertType {
/// The generic error message.
case generic
}

enum RoomChangePermissionsScreenViewAction {
/// Save the permissions.
case save
}

extension RoomChangePermissionsScreenViewState {
/// Creates a view state for a particular group of permissions.
/// - Parameters:
/// - currentPermissions: The current permissions for the room.
/// - group: The group of permissions that should be shown in the screen.
init(currentPermissions: RoomPermissions, group: RoomRolesAndPermissionsScreenPermissionsGroup) {
switch group {
case .roomDetails:
let settings = [
RoomPermissionsSetting(keyPath: \.roomName,
value: currentPermissions.roomName ?? RoomPermissions.defaultValue(for: \.roomName),
title: L10n.screenRoomChangePermissionsRoomName),
RoomPermissionsSetting(keyPath: \.roomAvatar,
value: currentPermissions.roomAvatar ?? RoomPermissions.defaultValue(for: \.roomAvatar),
title: L10n.screenRoomChangePermissionsRoomAvatar),
RoomPermissionsSetting(keyPath: \.roomTopic,
value: currentPermissions.roomTopic ?? RoomPermissions.defaultValue(for: \.roomTopic),
title: L10n.screenRoomChangePermissionsRoomTopic)
]

self.init(title: L10n.screenRoomChangePermissionsRoomDetails, currentPermissions: currentPermissions, bindings: .init(settings: settings))

case .messagesAndContent:
let settings = [
RoomPermissionsSetting(keyPath: \.eventsDefault,
value: currentPermissions.eventsDefault ?? RoomPermissions.defaultValue(for: \.eventsDefault),
title: L10n.screenRoomChangePermissionsSendMessages),
RoomPermissionsSetting(keyPath: \.redact,
value: currentPermissions.redact ?? RoomPermissions.defaultValue(for: \.redact),
title: L10n.screenRoomChangePermissionsDeleteMessages)
]

self.init(title: L10n.screenRoomChangePermissionsMessagesAndContent, currentPermissions: currentPermissions, bindings: .init(settings: settings))

case .memberModeration:
let settings = [
RoomPermissionsSetting(keyPath: \.invite,
value: currentPermissions.invite ?? RoomPermissions.defaultValue(for: \.invite),
title: L10n.screenRoomChangePermissionsInvitePeople),
RoomPermissionsSetting(keyPath: \.kick,
value: currentPermissions.kick ?? RoomPermissions.defaultValue(for: \.kick),
title: L10n.screenRoomChangePermissionsRemovePeople),
RoomPermissionsSetting(keyPath: \.ban,
value: currentPermissions.ban ?? RoomPermissions.defaultValue(for: \.ban),
title: L10n.screenRoomChangePermissionsBanPeople)
]

self.init(title: L10n.screenRoomChangePermissionsMemberModeration, currentPermissions: currentPermissions, bindings: .init(settings: settings))
}
}
}
Loading
Loading