More Moderation tweaks (#2566)

* Show room member role changes in the timeline.

* Fix a bug in room flow coordinator.

* Tidy up roles and permissions flow.

* Refresh the power levels in the room details screen.

* Automatically update permissions after saving.

* Remove extra button.

* Add a short delay to the roles and permissions screen snapshots.
The permissions rows are now in a loading state initially.
This commit is contained in:
Doug
2024-03-13 15:36:38 +00:00
committed by GitHub
parent 9d68d9e250
commit 1c914c314f
17 changed files with 212 additions and 43 deletions
@@ -26,7 +26,7 @@ struct RoomRolesAndPermissionsScreenCoordinatorParameters {
enum RoomRolesAndPermissionsScreenCoordinatorAction {
case editRoles(RoomRolesAndPermissionsScreenRole)
case editPermissions(RoomRolesAndPermissionsScreenPermissionsGroup)
case editPermissions(permissions: RoomPermissions, group: RoomRolesAndPermissionsScreenPermissionsGroup)
case demotedOwnUser
}
@@ -52,8 +52,8 @@ final class RoomRolesAndPermissionsScreenCoordinator: CoordinatorProtocol {
switch action {
case .editRoles(let role):
actionsSubject.send(.editRoles(role))
case .editPermissions(let permissionsGroup):
actionsSubject.send(.editPermissions(permissionsGroup))
case .editPermissions(let permissions, let group):
actionsSubject.send(.editPermissions(permissions: permissions, group: group))
case .demotedOwnUser:
actionsSubject.send(.demotedOwnUser)
}
@@ -20,7 +20,7 @@ enum RoomRolesAndPermissionsScreenViewModelAction {
/// The user would like to edit member roles.
case editRoles(RoomRolesAndPermissionsScreenRole)
/// The user would like to edit room permissions.
case editPermissions(RoomRolesAndPermissionsScreenPermissionsGroup)
case editPermissions(permissions: RoomPermissions, group: RoomRolesAndPermissionsScreenPermissionsGroup)
/// The user has demoted themself.
case demotedOwnUser
}
@@ -30,6 +30,8 @@ struct RoomRolesAndPermissionsScreenViewState: BindableState {
var administratorCount: Int?
/// The number of moderators in the room.
var moderatorCount: Int?
/// The permissions of the room when loaded.
var permissions: RoomPermissions?
var bindings = RoomRolesAndPermissionsScreenViewStateBindings()
}
@@ -33,12 +33,26 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
self.userIndicatorController = userIndicatorController
super.init(initialViewState: RoomRolesAndPermissionsScreenViewState())
roomProxy.membersPublisher.sink { [weak self] members in
self?.updateMembers(members)
}
.store(in: &cancellables)
// Automatically update the admin/moderator counts.
roomProxy.membersPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] members in
self?.updateMembers(members)
}
.store(in: &cancellables)
updateMembers(roomProxy.membersPublisher.value)
// Automatically update the room permissions
roomProxy.actionsPublisher
.filter { $0 == .roomInfoUpdate }
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
Task { await self?.updatePermissions() }
}
.store(in: &cancellables)
Task { await updatePermissions() }
}
// MARK: - Public
@@ -53,17 +67,17 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
state.bindings.alertInfo = AlertInfo(id: .resetConfirmation,
title: L10n.screenRoomRolesAndPermissionsChangeMyRole,
message: L10n.screenRoomChangeRoleConfirmDemoteSelfDescription,
primaryButton: .init(title: L10n.actionCancel, role: .cancel) { },
verticalButtons: [
.init(title: L10n.screenRoomRolesAndPermissionsChangeRoleDemoteToModerator, role: .destructive) {
Task { await self.updateOwnRole(.moderator) }
},
.init(title: L10n.screenRoomRolesAndPermissionsChangeRoleDemoteToMember, role: .destructive) {
Task { await self.updateOwnRole(.user) }
},
.init(title: L10n.actionCancel, role: .cancel) { }
}
])
case .editPermissions(let permissionsGroup):
actionsSubject.send(.editPermissions(permissionsGroup))
editPermissions(group: permissionsGroup)
case .reset:
state.bindings.alertInfo = AlertInfo(id: .resetConfirmation,
title: L10n.screenRoomRolesAndPermissionsResetConfirmTitle,
@@ -85,10 +99,16 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
private func updateOwnRole(_ role: RoomMemberDetails.Role) async {
showSavingIndicator()
// A task we can await until the room's info gets modified with the new power levels.
let infoTask = Task { await roomProxy.actionsPublisher.values.first { $0 == .roomInfoUpdate } }
switch await roomProxy.updatePowerLevelsForUsers([(userID: roomProxy.ownUserID, powerLevel: role.rustPowerLevel)]) {
case .success:
showSuccessIndicator()
_ = await infoTask.value
await roomProxy.updateMembers()
actionsSubject.send(.demotedOwnUser)
showSuccessIndicator()
case .failure:
state.bindings.alertInfo = AlertInfo(id: .error)
}
@@ -96,6 +116,26 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
hideSavingIndicator()
}
// MARK: - Permissions
private func updatePermissions() async {
switch await roomProxy.powerLevels() {
case .success(let powerLevels):
state.permissions = .init(powerLevels: powerLevels)
case .failure:
break
}
}
private func editPermissions(group: RoomRolesAndPermissionsScreenPermissionsGroup) {
guard let permissions = state.permissions else {
state.bindings.alertInfo = AlertInfo(id: .error)
MXLog.error("Missing permissions.")
return
}
actionsSubject.send(.editPermissions(permissions: permissions, group: group))
}
private func resetPermissions() async {
showSavingIndicator()
@@ -82,24 +82,30 @@ struct RoomRolesAndPermissionsScreen: View {
Section {
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsRoomDetails,
icon: \.info),
details: .isWaiting(context.viewState.permissions == nil),
kind: .navigationLink {
context.send(viewAction: .editPermissions(.roomDetails))
})
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.roomDetails)
.disabled(context.viewState.permissions == nil)
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsMessagesAndContent,
icon: \.chat),
details: .isWaiting(context.viewState.permissions == nil),
kind: .navigationLink {
context.send(viewAction: .editPermissions(.messagesAndContent))
})
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.messagesAndContent)
.disabled(context.viewState.permissions == nil)
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsMemberModeration,
icon: \.user),
details: .isWaiting(context.viewState.permissions == nil),
kind: .navigationLink {
context.send(viewAction: .editPermissions(.memberModeration))
})
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.memberModeration)
.disabled(context.viewState.permissions == nil)
} header: {
Text(L10n.screenRoomRolesAndPermissionsPermissionsHeader)
.compoundListSectionHeader()
@@ -126,5 +132,6 @@ struct RoomRolesAndPermissionsScreen_Previews: PreviewProvider, TestablePreview
NavigationStack {
RoomRolesAndPermissionsScreen(context: viewModel.context)
}
.snapshot(delay: 0.2)
}
}