mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
implemented a way to filter out roles that can't be assigned to permission, and disable permissions that are above the current power level of the user.
This commit is contained in:
@@ -119,10 +119,10 @@ class RoomRolesAndPermissionsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
stateMachine.addRoutes(event: .finishedChangingRoles, transitions: [.changingRoles => .rolesAndPermissionsScreen])
|
stateMachine.addRoutes(event: .finishedChangingRoles, transitions: [.changingRoles => .rolesAndPermissionsScreen])
|
||||||
|
|
||||||
stateMachine.addRoutes(event: .changePermissions, transitions: [.rolesAndPermissionsScreen => .changingPermissions]) { [weak self] context in
|
stateMachine.addRoutes(event: .changePermissions, transitions: [.rolesAndPermissionsScreen => .changingPermissions]) { [weak self] context in
|
||||||
guard let permissions = context.userInfo as? RoomPermissions else {
|
guard let (ownPowerLevel, permissions) = context.userInfo as? (RoomPowerLevel, RoomPermissions) else {
|
||||||
fatalError("Expected a group and the current permissions")
|
fatalError("Expected a group and the current permissions")
|
||||||
}
|
}
|
||||||
self?.presentChangePermissionsScreen(permissions: permissions)
|
self?.presentChangePermissionsScreen(ownPowerLevel: ownPowerLevel, permissions: permissions)
|
||||||
}
|
}
|
||||||
stateMachine.addRoutes(event: .finishedChangingPermissions, transitions: [.changingPermissions => .rolesAndPermissionsScreen])
|
stateMachine.addRoutes(event: .finishedChangingPermissions, transitions: [.changingPermissions => .rolesAndPermissionsScreen])
|
||||||
|
|
||||||
@@ -144,8 +144,8 @@ class RoomRolesAndPermissionsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
switch action {
|
switch action {
|
||||||
case .editRoles(let role):
|
case .editRoles(let role):
|
||||||
stateMachine.tryEvent(.changeRoles, userInfo: role)
|
stateMachine.tryEvent(.changeRoles, userInfo: role)
|
||||||
case .editPermissions(let permissions):
|
case .editPermissions(let ownPowerLevel, let permissions):
|
||||||
stateMachine.tryEvent(.changePermissions, userInfo: permissions)
|
stateMachine.tryEvent(.changePermissions, userInfo: (ownPowerLevel, permissions))
|
||||||
case .demotedOwnUser:
|
case .demotedOwnUser:
|
||||||
stateMachine.tryEvent(.demotedOwnUser)
|
stateMachine.tryEvent(.demotedOwnUser)
|
||||||
}
|
}
|
||||||
@@ -179,8 +179,9 @@ class RoomRolesAndPermissionsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentChangePermissionsScreen(permissions: RoomPermissions) {
|
private func presentChangePermissionsScreen(ownPowerLevel: RoomPowerLevel, permissions: RoomPermissions) {
|
||||||
let parameters = RoomChangePermissionsScreenCoordinatorParameters(permissions: permissions,
|
let parameters = RoomChangePermissionsScreenCoordinatorParameters(ownPowerLevel: ownPowerLevel,
|
||||||
|
permissions: permissions,
|
||||||
roomProxy: roomProxy,
|
roomProxy: roomProxy,
|
||||||
userIndicatorController: userIndicatorController,
|
userIndicatorController: userIndicatorController,
|
||||||
analytics: analytics)
|
analytics: analytics)
|
||||||
|
|||||||
+2
-3
@@ -10,6 +10,7 @@ import Combine
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct RoomChangePermissionsScreenCoordinatorParameters {
|
struct RoomChangePermissionsScreenCoordinatorParameters {
|
||||||
|
let ownPowerLevel: RoomPowerLevel
|
||||||
let permissions: RoomPermissions
|
let permissions: RoomPermissions
|
||||||
let roomProxy: JoinedRoomProxyProtocol
|
let roomProxy: JoinedRoomProxyProtocol
|
||||||
let userIndicatorController: UserIndicatorControllerProtocol
|
let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
@@ -21,7 +22,6 @@ enum RoomChangePermissionsScreenCoordinatorAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class RoomChangePermissionsScreenCoordinator: CoordinatorProtocol {
|
final class RoomChangePermissionsScreenCoordinator: CoordinatorProtocol {
|
||||||
private let parameters: RoomChangePermissionsScreenCoordinatorParameters
|
|
||||||
private var viewModel: RoomChangePermissionsScreenViewModelProtocol
|
private var viewModel: RoomChangePermissionsScreenViewModelProtocol
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
@@ -31,9 +31,8 @@ final class RoomChangePermissionsScreenCoordinator: CoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(parameters: RoomChangePermissionsScreenCoordinatorParameters) {
|
init(parameters: RoomChangePermissionsScreenCoordinatorParameters) {
|
||||||
self.parameters = parameters
|
|
||||||
|
|
||||||
viewModel = RoomChangePermissionsScreenViewModel(currentPermissions: parameters.permissions,
|
viewModel = RoomChangePermissionsScreenViewModel(currentPermissions: parameters.permissions,
|
||||||
|
ownPowerLevel: parameters.ownPowerLevel,
|
||||||
roomProxy: parameters.roomProxy,
|
roomProxy: parameters.roomProxy,
|
||||||
userIndicatorController: parameters.userIndicatorController,
|
userIndicatorController: parameters.userIndicatorController,
|
||||||
analytics: parameters.analytics)
|
analytics: parameters.analytics)
|
||||||
|
|||||||
+10
-1
@@ -69,7 +69,7 @@ extension RoomChangePermissionsScreenViewState {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - currentPermissions: The current permissions for the room.
|
/// - currentPermissions: The current permissions for the room.
|
||||||
/// - isSpace: if the room is a space or a normal room.
|
/// - isSpace: if the room is a space or a normal room.
|
||||||
init(currentPermissions: RoomPermissions, isSpace: Bool) {
|
init(ownPowerLevel: RoomPowerLevel, currentPermissions: RoomPermissions, isSpace: Bool) {
|
||||||
var settings = [RoomChangePermissionsScreenGroup: [RoomPermissionsSetting]]()
|
var settings = [RoomChangePermissionsScreenGroup: [RoomPermissionsSetting]]()
|
||||||
for group in RoomChangePermissionsScreenGroup.allCases {
|
for group in RoomChangePermissionsScreenGroup.allCases {
|
||||||
switch group {
|
switch group {
|
||||||
@@ -77,12 +77,15 @@ extension RoomChangePermissionsScreenViewState {
|
|||||||
settings[group] = [
|
settings[group] = [
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRoomName,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRoomName,
|
||||||
value: currentPermissions.roomName,
|
value: currentPermissions.roomName,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.roomName),
|
keyPath: \.roomName),
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRoomAvatar,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRoomAvatar,
|
||||||
value: currentPermissions.roomAvatar,
|
value: currentPermissions.roomAvatar,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.roomAvatar),
|
keyPath: \.roomAvatar),
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRoomTopic,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRoomTopic,
|
||||||
value: currentPermissions.roomTopic,
|
value: currentPermissions.roomTopic,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.roomTopic)
|
keyPath: \.roomTopic)
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -90,12 +93,15 @@ extension RoomChangePermissionsScreenViewState {
|
|||||||
settings[group] = [
|
settings[group] = [
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsInvitePeople,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsInvitePeople,
|
||||||
value: currentPermissions.invite,
|
value: currentPermissions.invite,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.invite),
|
keyPath: \.invite),
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRemovePeople,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsRemovePeople,
|
||||||
value: currentPermissions.kick,
|
value: currentPermissions.kick,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.kick),
|
keyPath: \.kick),
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsBanPeople,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsBanPeople,
|
||||||
value: currentPermissions.ban,
|
value: currentPermissions.ban,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.ban)
|
keyPath: \.ban)
|
||||||
]
|
]
|
||||||
case .messagesAndContent:
|
case .messagesAndContent:
|
||||||
@@ -103,9 +109,11 @@ extension RoomChangePermissionsScreenViewState {
|
|||||||
settings[group] = [
|
settings[group] = [
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsSendMessages,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsSendMessages,
|
||||||
value: currentPermissions.eventsDefault,
|
value: currentPermissions.eventsDefault,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.eventsDefault),
|
keyPath: \.eventsDefault),
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsDeleteMessages,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsDeleteMessages,
|
||||||
value: currentPermissions.redact,
|
value: currentPermissions.redact,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.redact)
|
keyPath: \.redact)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -114,6 +122,7 @@ extension RoomChangePermissionsScreenViewState {
|
|||||||
settings[group] = [
|
settings[group] = [
|
||||||
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsManageSpaceRooms,
|
RoomPermissionsSetting(title: L10n.screenRoomChangePermissionsManageSpaceRooms,
|
||||||
value: currentPermissions.spaceChild,
|
value: currentPermissions.spaceChild,
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
keyPath: \.spaceChild)
|
keyPath: \.spaceChild)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-10
@@ -23,13 +23,16 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(currentPermissions: RoomPermissions,
|
init(currentPermissions: RoomPermissions,
|
||||||
|
ownPowerLevel: RoomPowerLevel,
|
||||||
roomProxy: JoinedRoomProxyProtocol,
|
roomProxy: JoinedRoomProxyProtocol,
|
||||||
userIndicatorController: UserIndicatorControllerProtocol,
|
userIndicatorController: UserIndicatorControllerProtocol,
|
||||||
analytics: AnalyticsService) {
|
analytics: AnalyticsService) {
|
||||||
self.roomProxy = roomProxy
|
self.roomProxy = roomProxy
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
self.analytics = analytics
|
self.analytics = analytics
|
||||||
super.init(initialViewState: .init(currentPermissions: currentPermissions, isSpace: roomProxy.infoPublisher.value.isSpace))
|
super.init(initialViewState: .init(ownPowerLevel: ownPowerLevel,
|
||||||
|
currentPermissions: currentPermissions,
|
||||||
|
isSpace: roomProxy.infoPublisher.value.isSpace))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Public
|
// MARK: - Public
|
||||||
@@ -64,7 +67,7 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel
|
|||||||
.flatMap { $0 }
|
.flatMap { $0 }
|
||||||
.filter { state.currentPermissions[keyPath: $0.keyPath] != $0.value }
|
.filter { state.currentPermissions[keyPath: $0.keyPath] != $0.value }
|
||||||
for setting in changedSettings {
|
for setting in changedSettings {
|
||||||
changes[keyPath: setting.rustKeyPath] = setting.value.powerLevelValue
|
changes[keyPath: setting.rustKeyPath] = setting.value
|
||||||
}
|
}
|
||||||
|
|
||||||
switch await roomProxy.applyPowerLevelChanges(changes) {
|
switch await roomProxy.applyPowerLevelChanges(changes) {
|
||||||
@@ -106,14 +109,14 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel
|
|||||||
private func trackChanges(_ settings: [RoomPermissionsSetting]) {
|
private func trackChanges(_ settings: [RoomPermissionsSetting]) {
|
||||||
for setting in settings {
|
for setting in settings {
|
||||||
switch setting.keyPath {
|
switch setting.keyPath {
|
||||||
case \.ban: analytics.trackRoomModeration(action: .ChangePermissionsBanMembers, role: setting.value)
|
case \.ban: analytics.trackRoomModeration(action: .ChangePermissionsBanMembers, role: setting.roleValue)
|
||||||
case \.invite: analytics.trackRoomModeration(action: .ChangePermissionsInviteUsers, role: setting.value)
|
case \.invite: analytics.trackRoomModeration(action: .ChangePermissionsInviteUsers, role: setting.roleValue)
|
||||||
case \.kick: analytics.trackRoomModeration(action: .ChangePermissionsKickMembers, role: setting.value)
|
case \.kick: analytics.trackRoomModeration(action: .ChangePermissionsKickMembers, role: setting.roleValue)
|
||||||
case \.redact: analytics.trackRoomModeration(action: .ChangePermissionsRedactMessages, role: setting.value)
|
case \.redact: analytics.trackRoomModeration(action: .ChangePermissionsRedactMessages, role: setting.roleValue)
|
||||||
case \.eventsDefault: analytics.trackRoomModeration(action: .ChangePermissionsSendMessages, role: setting.value)
|
case \.eventsDefault: analytics.trackRoomModeration(action: .ChangePermissionsSendMessages, role: setting.roleValue)
|
||||||
case \.roomName: analytics.trackRoomModeration(action: .ChangePermissionsRoomName, role: setting.value)
|
case \.roomName: analytics.trackRoomModeration(action: .ChangePermissionsRoomName, role: setting.roleValue)
|
||||||
case \.roomAvatar: analytics.trackRoomModeration(action: .ChangePermissionsRoomAvatar, role: setting.value)
|
case \.roomAvatar: analytics.trackRoomModeration(action: .ChangePermissionsRoomAvatar, role: setting.roleValue)
|
||||||
case \.roomTopic: analytics.trackRoomModeration(action: .ChangePermissionsRoomTopic, role: setting.value)
|
case \.roomTopic: analytics.trackRoomModeration(action: .ChangePermissionsRoomTopic, role: setting.roleValue)
|
||||||
default: MXLog.warning("Unexpected change: \(setting.keyPath).")
|
default: MXLog.warning("Unexpected change: \(setting.keyPath).")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -32,7 +32,9 @@ struct RoomChangePermissionsScreen: View {
|
|||||||
Section {
|
Section {
|
||||||
ForEach(settings) { $setting in
|
ForEach(settings) { $setting in
|
||||||
ListRow(label: .plain(title: setting.title),
|
ListRow(label: .plain(title: setting.title),
|
||||||
kind: .picker(selection: $setting.value, items: setting.allValues))
|
kind: .picker(selection: $setting.roleValue,
|
||||||
|
items: setting.availableValues))
|
||||||
|
.disabled(setting.isDisabled)
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text(group.name)
|
Text(group.name)
|
||||||
@@ -64,6 +66,7 @@ struct RoomChangePermissionsScreen: View {
|
|||||||
|
|
||||||
struct RoomChangePermissionsScreen_Previews: PreviewProvider, TestablePreview {
|
struct RoomChangePermissionsScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
static let roomViewModel = makeViewModel(isSpace: false)
|
static let roomViewModel = makeViewModel(isSpace: false)
|
||||||
|
static let roomAsUserViewModel = makeViewModel(isSpace: false, ownPowerLevel: RoomRole.user.powerLevel)
|
||||||
static let spaceViewModel = makeViewModel(isSpace: true)
|
static let spaceViewModel = makeViewModel(isSpace: true)
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
@@ -72,14 +75,20 @@ struct RoomChangePermissionsScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
.previewDisplayName("Room")
|
.previewDisplayName("Room")
|
||||||
|
|
||||||
|
NavigationStack {
|
||||||
|
RoomChangePermissionsScreen(context: roomAsUserViewModel.context)
|
||||||
|
}
|
||||||
|
.previewDisplayName("Room as User")
|
||||||
|
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
RoomChangePermissionsScreen(context: spaceViewModel.context)
|
RoomChangePermissionsScreen(context: spaceViewModel.context)
|
||||||
}
|
}
|
||||||
.previewDisplayName("Space")
|
.previewDisplayName("Space")
|
||||||
}
|
}
|
||||||
|
|
||||||
static func makeViewModel(isSpace: Bool) -> RoomChangePermissionsScreenViewModel {
|
static func makeViewModel(isSpace: Bool, ownPowerLevel: RoomPowerLevel = RoomRole.creator.powerLevel) -> RoomChangePermissionsScreenViewModel {
|
||||||
RoomChangePermissionsScreenViewModel(currentPermissions: .init(powerLevels: .mock),
|
RoomChangePermissionsScreenViewModel(currentPermissions: .init(powerLevels: .mock),
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
roomProxy: JoinedRoomProxyMock(.init(isSpace: isSpace)),
|
roomProxy: JoinedRoomProxyMock(.init(isSpace: isSpace)),
|
||||||
userIndicatorController: UserIndicatorControllerMock(),
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
analytics: ServiceLocator.shared.analytics)
|
analytics: ServiceLocator.shared.analytics)
|
||||||
|
|||||||
+3
-3
@@ -17,7 +17,7 @@ struct RoomRolesAndPermissionsScreenCoordinatorParameters {
|
|||||||
|
|
||||||
enum RoomRolesAndPermissionsScreenCoordinatorAction {
|
enum RoomRolesAndPermissionsScreenCoordinatorAction {
|
||||||
case editRoles(RoomRolesAndPermissionsScreenRole)
|
case editRoles(RoomRolesAndPermissionsScreenRole)
|
||||||
case editPermissions(permissions: RoomPermissions)
|
case editPermissions(ownPowerLevel: RoomPowerLevel, permissions: RoomPermissions)
|
||||||
case demotedOwnUser
|
case demotedOwnUser
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +44,8 @@ final class RoomRolesAndPermissionsScreenCoordinator: CoordinatorProtocol {
|
|||||||
switch action {
|
switch action {
|
||||||
case .editRoles(let role):
|
case .editRoles(let role):
|
||||||
actionsSubject.send(.editRoles(role))
|
actionsSubject.send(.editRoles(role))
|
||||||
case .editPermissions(let permissions):
|
case .editPermissions(let ownPowerLevel, let permissions):
|
||||||
actionsSubject.send(.editPermissions(permissions: permissions))
|
actionsSubject.send(.editPermissions(ownPowerLevel: ownPowerLevel, permissions: permissions))
|
||||||
case .demotedOwnUser:
|
case .demotedOwnUser:
|
||||||
actionsSubject.send(.demotedOwnUser)
|
actionsSubject.send(.demotedOwnUser)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -12,13 +12,13 @@ enum RoomRolesAndPermissionsScreenViewModelAction {
|
|||||||
/// The user would like to edit member roles.
|
/// The user would like to edit member roles.
|
||||||
case editRoles(RoomRolesAndPermissionsScreenRole)
|
case editRoles(RoomRolesAndPermissionsScreenRole)
|
||||||
/// The user would like to edit room permissions.
|
/// The user would like to edit room permissions.
|
||||||
case editPermissions(permissions: RoomPermissions)
|
case editPermissions(ownPowerLevel: RoomPowerLevel, permissions: RoomPermissions)
|
||||||
/// The user has demoted themself.
|
/// The user has demoted themself.
|
||||||
case demotedOwnUser
|
case demotedOwnUser
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoomRolesAndPermissionsScreenViewState: BindableState {
|
struct RoomRolesAndPermissionsScreenViewState: BindableState {
|
||||||
var ownRole: RoomRole
|
var ownPowerLevel: RoomPowerLevel
|
||||||
|
|
||||||
var administratorsAndOwnersCount: Int?
|
var administratorsAndOwnersCount: Int?
|
||||||
/// The number of administrators in the room.
|
/// The number of administrators in the room.
|
||||||
|
|||||||
+3
-3
@@ -26,7 +26,7 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
self.roomProxy = roomProxy
|
self.roomProxy = roomProxy
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
self.analytics = analytics
|
self.analytics = analytics
|
||||||
super.init(initialViewState: RoomRolesAndPermissionsScreenViewState(ownRole: roomProxy.membersPublisher.value.first { $0.userID == roomProxy.ownUserID }?.role ?? .administrator,
|
super.init(initialViewState: RoomRolesAndPermissionsScreenViewState(ownPowerLevel: roomProxy.membersPublisher.value.first { $0.userID == roomProxy.ownUserID }?.powerLevel ?? .value(Int(RoomRole.administrator.powerLevelValue)),
|
||||||
permissions: initialPermissions))
|
permissions: initialPermissions))
|
||||||
|
|
||||||
// Automatically update the admin/moderator counts.
|
// Automatically update the admin/moderator counts.
|
||||||
@@ -91,7 +91,7 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
state.administratorCount = members.filter { $0.role == .administrator && $0.isActive }.count
|
state.administratorCount = members.filter { $0.role == .administrator && $0.isActive }.count
|
||||||
state.moderatorCount = members.filter { $0.role == .moderator && $0.isActive }.count
|
state.moderatorCount = members.filter { $0.role == .moderator && $0.isActive }.count
|
||||||
if let ownUser = members.first(where: { $0.userID == roomProxy.ownUserID }) {
|
if let ownUser = members.first(where: { $0.userID == roomProxy.ownUserID }) {
|
||||||
state.ownRole = ownUser.role
|
state.ownPowerLevel = ownUser.powerLevel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
MXLog.error("Missing permissions.")
|
MXLog.error("Missing permissions.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
actionsSubject.send(.editPermissions(permissions: permissions))
|
actionsSubject.send(.editPermissions(ownPowerLevel: state.ownPowerLevel, permissions: permissions))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func resetPermissions() async {
|
private func resetPermissions() async {
|
||||||
|
|||||||
+2
-2
@@ -27,7 +27,7 @@ struct RoomRolesAndPermissionsScreen: View {
|
|||||||
|
|
||||||
private var rolesSection: some View {
|
private var rolesSection: some View {
|
||||||
Section {
|
Section {
|
||||||
if context.viewState.ownRole == .creator {
|
if context.viewState.ownPowerLevel.role == .creator {
|
||||||
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsAdminsAndOwners,
|
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsAdminsAndOwners,
|
||||||
icon: \.admin),
|
icon: \.admin),
|
||||||
details: administratorOrOwnersDetails,
|
details: administratorOrOwnersDetails,
|
||||||
@@ -53,7 +53,7 @@ struct RoomRolesAndPermissionsScreen: View {
|
|||||||
})
|
})
|
||||||
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.moderators)
|
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.moderators)
|
||||||
|
|
||||||
if context.viewState.ownRole != .creator {
|
if context.viewState.ownPowerLevel.role != .creator {
|
||||||
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsChangeMyRole,
|
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsChangeMyRole,
|
||||||
icon: \.edit),
|
icon: \.edit),
|
||||||
kind: .button {
|
kind: .button {
|
||||||
|
|||||||
@@ -10,24 +10,29 @@ import Foundation
|
|||||||
import MatrixRustSDK
|
import MatrixRustSDK
|
||||||
|
|
||||||
struct RoomPermissionsSetting: Identifiable {
|
struct RoomPermissionsSetting: Identifiable {
|
||||||
var id: KeyPath<RoomPermissions, RoomRole> { keyPath }
|
static let allValues: [(title: String, tag: RoomRole)] = [(title: L10n.screenRoomChangePermissionsAdministrators, tag: .administrator),
|
||||||
|
(title: L10n.screenRoomChangePermissionsModerators, tag: .moderator),
|
||||||
|
(title: L10n.screenRoomChangePermissionsEveryone, tag: .user)]
|
||||||
|
var id: KeyPath<RoomPermissions, Int64> { keyPath }
|
||||||
|
|
||||||
/// The title of this setting.
|
/// The title of this setting.
|
||||||
let title: String
|
let title: String
|
||||||
|
|
||||||
/// The selected role of this setting.
|
/// The selected role of this setting.
|
||||||
var value: RoomRole
|
var value: Int64
|
||||||
/// All of the available roles that this setting can be configured with.
|
|
||||||
var allValues: [(title: String, tag: RoomRole)] {
|
let ownPowerLevel: RoomPowerLevel
|
||||||
[
|
|
||||||
(title: L10n.screenRoomChangePermissionsAdministrators, tag: .administrator),
|
var roleValue: RoomRole {
|
||||||
(title: L10n.screenRoomChangePermissionsModerators, tag: .moderator),
|
get {
|
||||||
(title: L10n.screenRoomChangePermissionsEveryone, tag: .user)
|
RoomRole(powerLevelValue: value)
|
||||||
]
|
} set {
|
||||||
|
value = newValue.powerLevelValue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `RoomPermissions` property that this setting is for.
|
/// The `RoomPermissions` property that this setting is for.
|
||||||
let keyPath: KeyPath<RoomPermissions, RoomRole>
|
let keyPath: KeyPath<RoomPermissions, Int64>
|
||||||
/// The `RoomPowerLevelChanges` property that this setting is saved into.
|
/// The `RoomPowerLevelChanges` property that this setting is saved into.
|
||||||
var rustKeyPath: WritableKeyPath<RoomPowerLevelChanges, Int64?> {
|
var rustKeyPath: WritableKeyPath<RoomPowerLevelChanges, Int64?> {
|
||||||
switch keyPath {
|
switch keyPath {
|
||||||
@@ -45,46 +50,75 @@ struct RoomPermissionsSetting: Identifiable {
|
|||||||
default: fatalError("Unexpected key path: \(keyPath)")
|
default: fatalError("Unexpected key path: \(keyPath)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Can the setting be edited
|
||||||
|
var isDisabled: Bool {
|
||||||
|
switch ownPowerLevel {
|
||||||
|
case .value(let ownValue):
|
||||||
|
ownValue < value
|
||||||
|
case .infinite:
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// All of the available roles that this setting can be configured with.
|
||||||
|
var availableValues: [(title: String, tag: RoomRole)] {
|
||||||
|
if isDisabled {
|
||||||
|
Self.allValues.filter { $0.tag == RoomRole(powerLevelValue: value) }
|
||||||
|
} else {
|
||||||
|
Self.allValues.filter { $0.tag <= ownPowerLevel.role }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(title: String,
|
||||||
|
value: Int64,
|
||||||
|
ownPowerLevel: RoomPowerLevel,
|
||||||
|
keyPath: KeyPath<RoomPermissions, Int64>) {
|
||||||
|
self.ownPowerLevel = ownPowerLevel
|
||||||
|
self.title = title
|
||||||
|
self.value = value
|
||||||
|
self.keyPath = keyPath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoomPermissions {
|
struct RoomPermissions {
|
||||||
/// The level required to ban a user.
|
/// The level required to ban a user.
|
||||||
var ban: RoomRole
|
var ban: Int64
|
||||||
/// The level required to invite a user.
|
/// The level required to invite a user.
|
||||||
var invite: RoomRole
|
var invite: Int64
|
||||||
/// The level required to kick a user.
|
/// The level required to kick a user.
|
||||||
var kick: RoomRole
|
var kick: Int64
|
||||||
/// The level required to redact an event.
|
/// The level required to redact an event.
|
||||||
var redact: RoomRole
|
var redact: Int64
|
||||||
/// The default level required to send message events.
|
/// The default level required to send message events.
|
||||||
var eventsDefault: RoomRole
|
var eventsDefault: Int64
|
||||||
/// The default level required to send state events.
|
/// The default level required to send state events.
|
||||||
var stateDefault: RoomRole
|
var stateDefault: Int64
|
||||||
/// The default power level for every user in the room.
|
/// The default power level for every user in the room.
|
||||||
var usersDefault: RoomRole
|
var usersDefault: Int64
|
||||||
/// The level required to change the room's name.
|
/// The level required to change the room's name.
|
||||||
var roomName: RoomRole
|
var roomName: Int64
|
||||||
/// The level required to change the room's avatar.
|
/// The level required to change the room's avatar.
|
||||||
var roomAvatar: RoomRole
|
var roomAvatar: Int64
|
||||||
/// The level required to change the room's topic.
|
/// The level required to change the room's topic.
|
||||||
var roomTopic: RoomRole
|
var roomTopic: Int64
|
||||||
/// The level required to add/remove childrens from a space.
|
/// The level required to add/remove childrens from a space.
|
||||||
var spaceChild: RoomRole
|
var spaceChild: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RoomPermissions {
|
extension RoomPermissions {
|
||||||
/// Create permissions from the room's power levels.
|
/// Create permissions from the room's power levels.
|
||||||
init(powerLevels: RoomPowerLevelsValues) {
|
init(powerLevels: RoomPowerLevelsValues) {
|
||||||
ban = RoomRole(powerLevelValue: powerLevels.ban)
|
ban = powerLevels.ban
|
||||||
invite = RoomRole(powerLevelValue: powerLevels.invite)
|
invite = powerLevels.invite
|
||||||
kick = RoomRole(powerLevelValue: powerLevels.kick)
|
kick = powerLevels.kick
|
||||||
redact = RoomRole(powerLevelValue: powerLevels.redact)
|
redact = powerLevels.redact
|
||||||
eventsDefault = RoomRole(powerLevelValue: powerLevels.eventsDefault)
|
eventsDefault = powerLevels.eventsDefault
|
||||||
stateDefault = RoomRole(powerLevelValue: powerLevels.stateDefault)
|
stateDefault = powerLevels.stateDefault
|
||||||
usersDefault = RoomRole(powerLevelValue: powerLevels.usersDefault)
|
usersDefault = powerLevels.usersDefault
|
||||||
roomName = RoomRole(powerLevelValue: powerLevels.roomName)
|
roomName = powerLevels.roomName
|
||||||
roomAvatar = RoomRole(powerLevelValue: powerLevels.roomAvatar)
|
roomAvatar = powerLevels.roomAvatar
|
||||||
roomTopic = RoomRole(powerLevelValue: powerLevels.roomTopic)
|
roomTopic = powerLevels.roomTopic
|
||||||
spaceChild = RoomRole(powerLevelValue: powerLevels.spaceChild)
|
spaceChild = powerLevels.spaceChild
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ enum RoomPowerLevel: Hashable, Comparable {
|
|||||||
case .value(let value): .value(value: Int64(value))
|
case .value(let value): .value(value: Int64(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var role: RoomRole {
|
||||||
|
RoomRole(powerLevel: self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PowerLevel {
|
extension PowerLevel {
|
||||||
|
|||||||
@@ -110,21 +110,25 @@ extension RoomRole {
|
|||||||
/// To be used when setting the power level of a user to get the suggested equivalent power level value for that specific role
|
/// To be used when setting the power level of a user to get the suggested equivalent power level value for that specific role
|
||||||
/// NOTE: Do not use for comparison, use the true power level instead.
|
/// NOTE: Do not use for comparison, use the true power level instead.
|
||||||
var powerLevelValue: Int64 {
|
var powerLevelValue: Int64 {
|
||||||
guard self != .owner else {
|
switch powerLevel {
|
||||||
// Would be better if the SDK would return this, maybe a `suggestedPowerLevelValueForRole` function would solve the problem
|
|
||||||
return 150
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
switch try suggestedPowerLevelForRole(role: rustRole) {
|
|
||||||
case .infinite:
|
case .infinite:
|
||||||
fatalError("Impossible")
|
fatalError("Impossible")
|
||||||
case .value(let value):
|
case .value(let value):
|
||||||
return value
|
return Int64(value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var powerLevel: RoomPowerLevel {
|
||||||
|
guard self != .owner else {
|
||||||
|
// Would be better if the SDK would return this, maybe a `suggestedPowerLevelValueForRole` function would solve the problem
|
||||||
|
return .value(150)
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
return try RoomPowerLevel(rustPowerLevel: suggestedPowerLevelForRole(role: rustRole))
|
||||||
} catch {
|
} catch {
|
||||||
MXLog.error("Falied to convert role to power level value: \(error)")
|
MXLog.error("Falied to convert role to power level value: \(error)")
|
||||||
return 0
|
return .value(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:f2897748d30f63afc9e7cd7319ae38467604617171ebc8ff8f885ec65e66d1b4
|
||||||
|
size 154964
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:1b8c95c8b2d15721ab01673783510e6ec06ee119fad5e7a5a2c1336a818e0489
|
||||||
|
size 179946
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:eabd9c2b8da430c9dbab03a0c085096b40c53e8e96574216463433f0c652df68
|
||||||
|
size 99283
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:3a4238000b13f41fe0ce60d4cfe5d9b0ea10571e67e147d59f13b235688fe89f
|
||||||
|
size 135114
|
||||||
@@ -26,18 +26,44 @@ class RoomChangePermissionsScreenViewModelTests: XCTestCase {
|
|||||||
XCTFail("There should be a setting for the room avatar.")
|
XCTFail("There should be a setting for the room avatar.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
XCTAssertEqual(context.settings[.roomDetails]?[index].value, .moderator)
|
XCTAssertEqual(context.settings[.roomDetails]?[index].roleValue, .moderator)
|
||||||
XCTAssertFalse(context.viewState.hasChanges)
|
XCTAssertFalse(context.viewState.hasChanges)
|
||||||
|
|
||||||
// When updating a setting.
|
// When updating a setting.
|
||||||
let setting = RoomPermissionsSetting(title: "", value: .user, keyPath: \.roomAvatar)
|
let setting = RoomPermissionsSetting(title: "",
|
||||||
|
value: RoomRole.user.powerLevelValue,
|
||||||
|
ownPowerLevel: RoomRole.creator.powerLevel,
|
||||||
|
keyPath: \.roomAvatar)
|
||||||
|
XCTAssertFalse(setting.isDisabled)
|
||||||
|
XCTAssertEqual(setting.availableValues.map(\.tag), RoomPermissionsSetting.allValues.map(\.tag))
|
||||||
context.settings[.roomDetails]?[index] = setting
|
context.settings[.roomDetails]?[index] = setting
|
||||||
|
|
||||||
// Then the setting should update and the changes should be flagged.
|
// Then the setting should update and the changes should be flagged.
|
||||||
XCTAssertEqual(context.settings[.roomDetails]?[index].value, .user)
|
XCTAssertEqual(context.settings[.roomDetails]?[index].roleValue, .user)
|
||||||
XCTAssertTrue(context.viewState.hasChanges)
|
XCTAssertTrue(context.viewState.hasChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testSettingsCantBeChanged() {
|
||||||
|
setUp(isSpace: false, ownPowerLevel: .value(25))
|
||||||
|
// Given a screen with no changes.
|
||||||
|
guard let index = context.settings[.roomDetails]?.firstIndex(where: { $0.keyPath == \.roomAvatar }) else {
|
||||||
|
XCTFail("There should be a setting for the room avatar.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
XCTAssertEqual(context.settings[.roomDetails]?[index].roleValue, .moderator)
|
||||||
|
XCTAssertEqual(context.settings[.roomDetails]?[index].isDisabled, true)
|
||||||
|
XCTAssertEqual(context.settings[.roomDetails]?[index].availableValues.count, 1)
|
||||||
|
XCTAssertFalse(context.viewState.hasChanges)
|
||||||
|
|
||||||
|
guard let index = context.settings[.messagesAndContent]?.firstIndex(where: { $0.keyPath == \.eventsDefault }) else {
|
||||||
|
XCTFail("There should be a setting for the events.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
XCTAssertEqual(context.settings[.messagesAndContent]?[index].roleValue, .user)
|
||||||
|
XCTAssertEqual(context.settings[.messagesAndContent]?[index].isDisabled, false)
|
||||||
|
XCTAssertEqual(context.settings[.messagesAndContent]?[index].availableValues.count, 1)
|
||||||
|
}
|
||||||
|
|
||||||
func testSave() async throws {
|
func testSave() async throws {
|
||||||
setUp(isSpace: false)
|
setUp(isSpace: false)
|
||||||
// Given a screen with changes.
|
// Given a screen with changes.
|
||||||
@@ -45,8 +71,13 @@ class RoomChangePermissionsScreenViewModelTests: XCTestCase {
|
|||||||
XCTFail("There should be a setting for the room avatar.")
|
XCTFail("There should be a setting for the room avatar.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.settings[.roomDetails]?[index] = RoomPermissionsSetting(title: "", value: .user, keyPath: \.roomAvatar)
|
context.settings[.roomDetails]?[index] = RoomPermissionsSetting(title: "",
|
||||||
XCTAssertEqual(context.settings[.roomDetails]?[index].value, .user)
|
value: RoomRole.user.powerLevelValue,
|
||||||
|
ownPowerLevel: RoomRole.creator.powerLevel,
|
||||||
|
keyPath: \.roomAvatar)
|
||||||
|
XCTAssertEqual(context.settings[.roomDetails]?[index].roleValue, .user)
|
||||||
|
XCTAssertEqual(context.settings[.roomDetails]?[index].isDisabled, false)
|
||||||
|
XCTAssertEqual(context.settings[.roomDetails]?[index].availableValues.map(\.tag), RoomPermissionsSetting.allValues.map(\.tag))
|
||||||
XCTAssertTrue(context.viewState.hasChanges)
|
XCTAssertTrue(context.viewState.hasChanges)
|
||||||
XCTAssertEqual(context.settings.count, 3)
|
XCTAssertEqual(context.settings.count, 3)
|
||||||
|
|
||||||
@@ -89,9 +120,10 @@ class RoomChangePermissionsScreenViewModelTests: XCTestCase {
|
|||||||
XCTAssertNotNil(context.settings[.manageSpace])
|
XCTAssertNotNil(context.settings[.manageSpace])
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setUp(isSpace: Bool) {
|
private func setUp(isSpace: Bool, ownPowerLevel: RoomPowerLevel = RoomRole.creator.powerLevel) {
|
||||||
roomProxy = JoinedRoomProxyMock(.init(isSpace: isSpace))
|
roomProxy = JoinedRoomProxyMock(.init(isSpace: isSpace))
|
||||||
viewModel = RoomChangePermissionsScreenViewModel(currentPermissions: .init(powerLevels: .mock),
|
viewModel = RoomChangePermissionsScreenViewModel(currentPermissions: .init(powerLevels: .mock),
|
||||||
|
ownPowerLevel: ownPowerLevel,
|
||||||
roomProxy: roomProxy,
|
roomProxy: roomProxy,
|
||||||
userIndicatorController: UserIndicatorControllerMock(),
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
analytics: ServiceLocator.shared.analytics)
|
analytics: ServiceLocator.shared.analytics)
|
||||||
|
|||||||
@@ -30,16 +30,16 @@ class RoomPermissionsTests: XCTestCase {
|
|||||||
let permissions = RoomPermissions(powerLevels: powerLevels)
|
let permissions = RoomPermissions(powerLevels: powerLevels)
|
||||||
|
|
||||||
// Then the permissions should be created with values mapped to the correct role.
|
// Then the permissions should be created with values mapped to the correct role.
|
||||||
XCTAssertEqual(permissions.ban, .administrator)
|
XCTAssertEqual(permissions.ban, RoomRole.administrator.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.invite, .administrator)
|
XCTAssertEqual(permissions.invite, RoomRole.administrator.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.kick, .administrator)
|
XCTAssertEqual(permissions.kick, RoomRole.administrator.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.redact, .moderator)
|
XCTAssertEqual(permissions.redact, RoomRole.moderator.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.eventsDefault, .moderator)
|
XCTAssertEqual(permissions.eventsDefault, RoomRole.moderator.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.stateDefault, .moderator)
|
XCTAssertEqual(permissions.stateDefault, RoomRole.moderator.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.usersDefault, .user)
|
XCTAssertEqual(permissions.usersDefault, RoomRole.user.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.roomName, .user)
|
XCTAssertEqual(permissions.roomName, RoomRole.user.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.roomAvatar, .user)
|
XCTAssertEqual(permissions.roomAvatar, RoomRole.user.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.roomTopic, .user)
|
XCTAssertEqual(permissions.roomTopic, RoomRole.user.powerLevelValue)
|
||||||
XCTAssertEqual(permissions.spaceChild, .administrator)
|
XCTAssertEqual(permissions.spaceChild, RoomRole.administrator.powerLevelValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user