mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Add RoomRolesAndPermissionsFlowCoordinator. (#2539)
This commit is contained in:
@@ -50,6 +50,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let analytics: AnalyticsService
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
private var rolesAndPermissionsFlowCoordinator: RoomRolesAndPermissionsFlowCoordinator?
|
||||
|
||||
private let stateMachine: StateMachine<State, Event> = .init(state: .initial)
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -225,6 +227,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case (.pollsHistoryForm(let roomID), .dismissPollForm):
|
||||
return .pollsHistory(roomID: roomID)
|
||||
|
||||
case (.roomDetails(let roomID, _), .presentRolesAndPermissionsScreen):
|
||||
return .rolesAndPermissions(roomID: roomID)
|
||||
case (.rolesAndPermissions(let roomID), .dismissRolesAndPermissionsScreen):
|
||||
return .roomDetails(roomID: roomID, isRoot: false)
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@@ -343,6 +350,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case (.pollsHistoryForm, .dismissPollForm, .pollsHistory):
|
||||
break
|
||||
|
||||
case (.roomDetails, .presentRolesAndPermissionsScreen, .rolesAndPermissions):
|
||||
presentRolesAndPermissionsScreen()
|
||||
case (.rolesAndPermissions, .dismissRolesAndPermissionsScreen, .roomDetails):
|
||||
break
|
||||
|
||||
default:
|
||||
fatalError("Unknown transition: \(context)")
|
||||
}
|
||||
@@ -527,7 +539,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
userIndicatorController: userIndicatorController,
|
||||
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: appSettings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder()))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: appSettings)
|
||||
let coordinator = RoomDetailsScreenCoordinator(parameters: params)
|
||||
coordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
@@ -545,6 +558,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateMachine.tryEvent(.presentInviteUsersScreen)
|
||||
case .presentPollsHistory:
|
||||
stateMachine.tryEvent(.presentPollsHistory)
|
||||
case .presentRolesAndPermissionsScreen:
|
||||
stateMachine.tryEvent(.presentRolesAndPermissionsScreen)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
@@ -1155,6 +1170,25 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
message: L10n.commonUnableToInviteMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private func presentRolesAndPermissionsScreen() {
|
||||
guard let roomProxy else { fatalError() }
|
||||
|
||||
let parameters = RoomRolesAndPermissionsFlowCoordinatorParameters(roomProxy: roomProxy,
|
||||
navigationStackCoordinator: navigationStackCoordinator,
|
||||
userIndicatorController: userIndicatorController)
|
||||
let coordinator = RoomRolesAndPermissionsFlowCoordinator(parameters: parameters)
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
switch action {
|
||||
case .complete:
|
||||
self?.rolesAndPermissionsFlowCoordinator = nil
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
rolesAndPermissionsFlowCoordinator = coordinator
|
||||
coordinator.start()
|
||||
}
|
||||
}
|
||||
|
||||
private extension RoomFlowCoordinator {
|
||||
@@ -1189,6 +1223,7 @@ private extension RoomFlowCoordinator {
|
||||
case pollForm(roomID: String)
|
||||
case pollsHistory(roomID: String)
|
||||
case pollsHistoryForm(roomID: String)
|
||||
case rolesAndPermissions(roomID: String)
|
||||
}
|
||||
|
||||
struct EventUserInfo {
|
||||
@@ -1244,6 +1279,9 @@ private extension RoomFlowCoordinator {
|
||||
|
||||
case presentPollsHistory
|
||||
case dismissPollsHistory
|
||||
|
||||
case presentRolesAndPermissionsScreen
|
||||
case dismissRolesAndPermissionsScreen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
//
|
||||
// Copyright 2024 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import SwiftState
|
||||
|
||||
enum RoomRolesAndPermissionsFlowCoordinatorAction: Equatable {
|
||||
/// The flow is complete.
|
||||
case complete
|
||||
}
|
||||
|
||||
struct RoomRolesAndPermissionsFlowCoordinatorParameters {
|
||||
let roomProxy: RoomProxyProtocol
|
||||
let navigationStackCoordinator: NavigationStackCoordinator
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
}
|
||||
|
||||
class RoomRolesAndPermissionsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private let navigationStackCoordinator: NavigationStackCoordinator
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
enum State: StateType {
|
||||
/// The state machine hasn't started.
|
||||
case initial
|
||||
/// The root screen for this flow.
|
||||
case rolesAndPermissionsScreen
|
||||
/// Changing member roles.
|
||||
case changingRoles
|
||||
/// Changing room permissions.
|
||||
case changingPermissions
|
||||
}
|
||||
|
||||
enum Event: EventType {
|
||||
/// The flow is being started.
|
||||
case start
|
||||
/// The user would like to change member roles.
|
||||
case changeRoles
|
||||
/// The user finished changing member roles.
|
||||
case finishedChangingRoles
|
||||
/// The user would like to change room permissions.
|
||||
case changePermissions
|
||||
/// The user finished changing room permissions
|
||||
case finishedChangingPermissions
|
||||
}
|
||||
|
||||
private let stateMachine: StateMachine<State, Event>
|
||||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
private let actionsSubject: PassthroughSubject<RoomRolesAndPermissionsFlowCoordinatorAction, Never> = .init()
|
||||
var actionsPublisher: AnyPublisher<RoomRolesAndPermissionsFlowCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(parameters: RoomRolesAndPermissionsFlowCoordinatorParameters) {
|
||||
roomProxy = parameters.roomProxy
|
||||
navigationStackCoordinator = parameters.navigationStackCoordinator
|
||||
userIndicatorController = parameters.userIndicatorController
|
||||
|
||||
stateMachine = .init(state: .initial)
|
||||
configureStateMachine()
|
||||
}
|
||||
|
||||
func start() {
|
||||
stateMachine.tryEvent(.start)
|
||||
}
|
||||
|
||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||
// There aren't any routes to this screen, so always clear the stack.
|
||||
clearRoute(animated: animated)
|
||||
}
|
||||
|
||||
func clearRoute(animated: Bool) {
|
||||
// As we push screens on top of an existing stack, popping to root wouldn't be safe.
|
||||
switch stateMachine.state {
|
||||
case .initial:
|
||||
break
|
||||
case .rolesAndPermissionsScreen:
|
||||
navigationStackCoordinator.pop(animated: animated)
|
||||
case .changingRoles, .changingPermissions:
|
||||
navigationStackCoordinator.pop(animated: animated) // ChangeRoles or ChangePermissions screen.
|
||||
navigationStackCoordinator.pop(animated: animated) // RolesAndPermissions screen.
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func configureStateMachine() {
|
||||
stateMachine.addRoutes(event: .start, transitions: [.initial => .rolesAndPermissionsScreen]) { [weak self] _ in
|
||||
self?.presentRolesAndPermissionsScreen()
|
||||
}
|
||||
|
||||
stateMachine.addRoutes(event: .changeRoles, transitions: [.rolesAndPermissionsScreen => .changingRoles]) { [weak self] context in
|
||||
guard let role = context.userInfo as? RoomRolesAndPermissionsScreenRole else { fatalError("Expected a role") }
|
||||
self?.presentChangeRolesScreen(role: role)
|
||||
}
|
||||
stateMachine.addRoutes(event: .finishedChangingRoles, transitions: [.changingRoles => .rolesAndPermissionsScreen])
|
||||
|
||||
stateMachine.addRoutes(event: .changePermissions, transitions: [.rolesAndPermissionsScreen => .changingPermissions]) { [weak self] context in
|
||||
guard let (group, permissions) = context.userInfo as? (RoomRolesAndPermissionsScreenPermissionsGroup, RoomPermissions) else {
|
||||
fatalError("Expected a group and the current permissions")
|
||||
}
|
||||
self?.presentChangePermissionsScreen(permissions: permissions, group: group)
|
||||
}
|
||||
stateMachine.addRoutes(event: .finishedChangingPermissions, transitions: [.changingPermissions => .rolesAndPermissionsScreen])
|
||||
|
||||
stateMachine.addErrorHandler { context in
|
||||
fatalError("Unexpected transition: \(context)")
|
||||
}
|
||||
}
|
||||
|
||||
private func presentRolesAndPermissionsScreen() {
|
||||
let parameters = RoomRolesAndPermissionsScreenCoordinatorParameters(roomProxy: roomProxy)
|
||||
let coordinator = RoomRolesAndPermissionsScreenCoordinator(parameters: parameters)
|
||||
coordinator.actions.sink { [stateMachine] action in
|
||||
switch action {
|
||||
case .editRoles(let role):
|
||||
stateMachine.tryEvent(.changeRoles, userInfo: role)
|
||||
case .editPermissions(let group):
|
||||
stateMachine.tryEvent(.changePermissions, userInfo: (group, RoomPermissions.default))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationStackCoordinator.push(coordinator) { [weak self] in
|
||||
self?.actionsSubject.send(.complete)
|
||||
}
|
||||
}
|
||||
|
||||
private func presentChangeRolesScreen(role: RoomRolesAndPermissionsScreenRole) {
|
||||
let mode = switch role {
|
||||
case .administrators: RoomMemberDetails.Role.administrator
|
||||
case .moderators: RoomMemberDetails.Role.moderator
|
||||
}
|
||||
|
||||
let parameters = RoomChangeRolesScreenCoordinatorParameters(mode: mode,
|
||||
roomProxy: roomProxy,
|
||||
userIndicatorController: userIndicatorController)
|
||||
let coordinator = RoomChangeRolesScreenCoordinator(parameters: parameters)
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .done:
|
||||
// When discarding changes is finalised, either use an event or remove this action.
|
||||
navigationStackCoordinator.pop()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationStackCoordinator.push(coordinator) { [stateMachine] in
|
||||
stateMachine.tryEvent(.finishedChangingRoles)
|
||||
}
|
||||
}
|
||||
|
||||
private func presentChangePermissionsScreen(permissions: RoomPermissions, group: RoomRolesAndPermissionsScreenPermissionsGroup) {
|
||||
let parameters = RoomChangePermissionsScreenCoordinatorParameters(permissions: permissions,
|
||||
permissionsGroup: group,
|
||||
roomProxy: roomProxy,
|
||||
userIndicatorController: userIndicatorController)
|
||||
let coordinator = RoomChangePermissionsScreenCoordinator(parameters: parameters)
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .cancel:
|
||||
// When discarding changes is finalised, either use an event or remove this action.
|
||||
navigationStackCoordinator.pop()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationStackCoordinator.push(coordinator) { [stateMachine] in
|
||||
stateMachine.tryEvent(.finishedChangingPermissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ enum A11yIdentifiers {
|
||||
static let roomScreen = RoomScreen()
|
||||
static let roomDetailsScreen = RoomDetailsScreen()
|
||||
static let roomNotificationSettingsScreen = RoomNotificationSettingsScreen()
|
||||
static let roomRolesAndPermissionsScreen = RoomRolesAndPermissionsScreen()
|
||||
static let serverConfirmationScreen = ServerConfirmationScreen()
|
||||
static let sessionVerificationScreen = SessionVerificationScreen()
|
||||
static let settingsScreen = SettingsScreen()
|
||||
@@ -185,6 +186,14 @@ enum A11yIdentifiers {
|
||||
let allowCustomSetting = "room_notification_settings-allow_custom"
|
||||
}
|
||||
|
||||
struct RoomRolesAndPermissionsScreen {
|
||||
let administrators = "room_roles_and_permissions-administrators"
|
||||
let moderators = "room_roles_and_permissions-moderators"
|
||||
let roomDetails = "room_roles_and_permissions-room_details"
|
||||
let messagesAndContent = "room_roles_and_permissions-messages_and_content"
|
||||
let memberModeration = "room_roles_and_permissions-member_moderation"
|
||||
}
|
||||
|
||||
struct ServerConfirmationScreen {
|
||||
let `continue` = "server_confirmation-continue"
|
||||
let changeServer = "server_confirmation-change_server"
|
||||
|
||||
+3
-3
@@ -33,10 +33,10 @@ enum RoomChangePermissionsScreenCoordinatorAction {
|
||||
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> {
|
||||
private let actionsSubject: PassthroughSubject<RoomChangePermissionsScreenCoordinatorAction, Never> = .init()
|
||||
var actionsPublisher: AnyPublisher<RoomChangePermissionsScreenCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ final class RoomChangePermissionsScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
func start() {
|
||||
viewModel.actions.sink { [weak self] action in
|
||||
viewModel.actionsPublisher.sink { [weak self] action in
|
||||
MXLog.info("Coordinator: received view model action: \(action)")
|
||||
|
||||
guard let self else { return }
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private var actionsSubject: PassthroughSubject<RoomChangePermissionsScreenViewModelAction, Never> = .init()
|
||||
|
||||
var actions: AnyPublisher<RoomChangePermissionsScreenViewModelAction, Never> {
|
||||
var actionsPublisher: AnyPublisher<RoomChangePermissionsScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ import Combine
|
||||
|
||||
@MainActor
|
||||
protocol RoomChangePermissionsScreenViewModelProtocol {
|
||||
var actions: AnyPublisher<RoomChangePermissionsScreenViewModelAction, Never> { get }
|
||||
var actionsPublisher: AnyPublisher<RoomChangePermissionsScreenViewModelAction, Never> { get }
|
||||
var context: RoomChangePermissionsScreenViewModelType.Context { get }
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ struct RoomDetailsScreenCoordinatorParameters {
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
let notificationSettings: NotificationSettingsProxyProtocol
|
||||
let attributedStringBuilder: AttributedStringBuilderProtocol
|
||||
let appSettings: AppSettings
|
||||
}
|
||||
|
||||
enum RoomDetailsScreenCoordinatorAction {
|
||||
@@ -34,6 +35,7 @@ enum RoomDetailsScreenCoordinatorAction {
|
||||
case presentNotificationSettingsScreen
|
||||
case presentInviteUsersScreen
|
||||
case presentPollsHistory
|
||||
case presentRolesAndPermissionsScreen
|
||||
}
|
||||
|
||||
final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
@@ -53,7 +55,8 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
analyticsService: parameters.analyticsService,
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
notificationSettingsProxy: parameters.notificationSettings,
|
||||
attributedStringBuilder: parameters.attributedStringBuilder)
|
||||
attributedStringBuilder: parameters.attributedStringBuilder,
|
||||
appSettings: parameters.appSettings)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -76,6 +79,8 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.send(.presentNotificationSettingsScreen)
|
||||
case .requestPollsHistoryPresentation:
|
||||
actionsSubject.send(.presentPollsHistory)
|
||||
case .requestRolesAndPermissionsPresentation:
|
||||
actionsSubject.send(.presentRolesAndPermissionsScreen)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -28,6 +28,7 @@ enum RoomDetailsScreenViewModelAction {
|
||||
case leftRoom
|
||||
case requestEditDetailsPresentation
|
||||
case requestPollsHistoryPresentation
|
||||
case requestRolesAndPermissionsPresentation
|
||||
}
|
||||
|
||||
// MARK: View
|
||||
@@ -47,6 +48,7 @@ struct RoomDetailsScreenViewState: BindableState {
|
||||
var canEditRoomName = false
|
||||
var canEditRoomTopic = false
|
||||
var canEditRoomAvatar = false
|
||||
var canEditRolesOrPermissions = false
|
||||
var notificationSettingsState: RoomDetailsNotificationSettingsState = .loading
|
||||
|
||||
var canEdit: Bool {
|
||||
@@ -177,10 +179,11 @@ enum RoomDetailsScreenViewAction {
|
||||
case ignoreConfirmed
|
||||
case unignoreConfirmed
|
||||
case processTapNotifications
|
||||
case processToogleMuteNotifications
|
||||
case processToggleMuteNotifications
|
||||
case displayAvatar
|
||||
case processTapPolls
|
||||
case toggleFavourite(isFavourite: Bool)
|
||||
case processTapRolesAndPermissions
|
||||
}
|
||||
|
||||
enum RoomDetailsScreenViewShortcut {
|
||||
|
||||
@@ -27,6 +27,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let notificationSettingsProxy: NotificationSettingsProxyProtocol
|
||||
private let attributedStringBuilder: AttributedStringBuilderProtocol
|
||||
private let appSettings: AppSettings
|
||||
|
||||
private var dmRecipient: RoomMemberProxyProtocol?
|
||||
|
||||
@@ -42,7 +43,8 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
analyticsService: AnalyticsService,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
notificationSettingsProxy: NotificationSettingsProxyProtocol,
|
||||
attributedStringBuilder: AttributedStringBuilderProtocol) {
|
||||
attributedStringBuilder: AttributedStringBuilderProtocol,
|
||||
appSettings: AppSettings) {
|
||||
self.roomProxy = roomProxy
|
||||
self.clientProxy = clientProxy
|
||||
self.mediaProvider = mediaProvider
|
||||
@@ -50,6 +52,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.notificationSettingsProxy = notificationSettingsProxy
|
||||
self.attributedStringBuilder = attributedStringBuilder
|
||||
self.appSettings = appSettings
|
||||
|
||||
let topic = attributedStringBuilder.fromPlain(roomProxy.topic)
|
||||
|
||||
@@ -111,7 +114,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
} else {
|
||||
actionsSubject.send(.requestNotificationSettingsPresentation)
|
||||
}
|
||||
case .processToogleMuteNotifications:
|
||||
case .processToggleMuteNotifications:
|
||||
Task { await toggleMuteNotifications() }
|
||||
case .displayAvatar:
|
||||
displayFullScreenAvatar()
|
||||
@@ -119,6 +122,8 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
actionsSubject.send(.requestPollsHistoryPresentation)
|
||||
case .toggleFavourite(let isFavourite):
|
||||
Task { await toggleFavourite(isFavourite) }
|
||||
case .processTapRolesAndPermissions:
|
||||
actionsSubject.send(.requestRolesAndPermissionsPresentation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +177,9 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
state.canEditRoomName = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomName) == .success(true)
|
||||
state.canEditRoomTopic = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomTopic) == .success(true)
|
||||
state.canEditRoomAvatar = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomAvatar) == .success(true)
|
||||
if appSettings.roomModerationEnabled {
|
||||
state.canEditRolesOrPermissions = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomPowerLevels) == .success(true)
|
||||
}
|
||||
state.canInviteUsers = await canInviteUsers
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ struct RoomDetailsScreen: View {
|
||||
|
||||
topicSection
|
||||
|
||||
notificationSection
|
||||
configurationSection
|
||||
|
||||
aboutSection
|
||||
|
||||
@@ -169,7 +169,7 @@ struct RoomDetailsScreen: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var notificationSection: some View {
|
||||
private var configurationSection: some View {
|
||||
Section {
|
||||
ListRow(label: .default(title: L10n.screenRoomDetailsNotificationTitle,
|
||||
icon: \.notifications),
|
||||
@@ -188,13 +188,21 @@ struct RoomDetailsScreen: View {
|
||||
.onChange(of: context.isFavourite) { newValue in
|
||||
context.send(viewAction: .toggleFavourite(isFavourite: newValue))
|
||||
}
|
||||
|
||||
if context.viewState.canEditRolesOrPermissions, context.viewState.dmRecipient == nil {
|
||||
ListRow(label: .default(title: L10n.screenRoomDetailsRolesAndPermissions,
|
||||
icon: \.admin),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .processTapRolesAndPermissions)
|
||||
})
|
||||
}
|
||||
}
|
||||
.disabled(context.viewState.notificationSettingsState.isLoading)
|
||||
}
|
||||
|
||||
private var toggleMuteButton: some View {
|
||||
Button {
|
||||
context.send(viewAction: .processToogleMuteNotifications)
|
||||
context.send(viewAction: .processToggleMuteNotifications)
|
||||
} label: {
|
||||
if context.viewState.isProcessingMuteToggleAction {
|
||||
ProgressView()
|
||||
@@ -311,7 +319,8 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .userDirectory,
|
||||
mentionBuilder: MentionBuilder()))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}()
|
||||
|
||||
static let dmRoomViewModel = {
|
||||
@@ -337,7 +346,8 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .userDirectory,
|
||||
mentionBuilder: MentionBuilder()))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}()
|
||||
|
||||
static let simpleRoomViewModel = {
|
||||
@@ -362,7 +372,8 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .userDirectory,
|
||||
mentionBuilder: MentionBuilder()))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ struct RoomRolesAndPermissionsScreenViewState: BindableState {
|
||||
|
||||
enum RoomRolesAndPermissionsScreenViewAction {
|
||||
case editRoles(RoomRolesAndPermissionsScreenRole)
|
||||
case editOwnUserRole
|
||||
case editPermissions(RoomRolesAndPermissionsScreenPermissionsGroup)
|
||||
case reset
|
||||
}
|
||||
|
||||
+2
@@ -47,6 +47,8 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
||||
switch viewAction {
|
||||
case .editRoles(let role):
|
||||
actionsSubject.send(.editRoles(role))
|
||||
case .editOwnUserRole:
|
||||
break
|
||||
case .editPermissions(let permissionsGroup):
|
||||
actionsSubject.send(.editPermissions(permissionsGroup))
|
||||
case .reset:
|
||||
|
||||
+11
@@ -40,6 +40,7 @@ struct RoomRolesAndPermissionsScreen: View {
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .editRoles(.administrators))
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.administrators)
|
||||
|
||||
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsModerators,
|
||||
icon: \.chatProblem),
|
||||
@@ -47,6 +48,13 @@ struct RoomRolesAndPermissionsScreen: View {
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .editRoles(.moderators))
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.moderators)
|
||||
|
||||
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsChangeMyRole,
|
||||
icon: \.edit),
|
||||
kind: .button {
|
||||
context.send(viewAction: .editOwnUserRole)
|
||||
})
|
||||
} header: {
|
||||
Text(L10n.screenRoomRolesAndPermissionsRolesHeader)
|
||||
.compoundListSectionHeader()
|
||||
@@ -76,18 +84,21 @@ struct RoomRolesAndPermissionsScreen: View {
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .editPermissions(.roomDetails))
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.roomDetails)
|
||||
|
||||
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsMessagesAndContent,
|
||||
icon: \.chat),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .editPermissions(.messagesAndContent))
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.messagesAndContent)
|
||||
|
||||
ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsMemberModeration,
|
||||
icon: \.user),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .editPermissions(.memberModeration))
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomRolesAndPermissionsScreen.memberModeration)
|
||||
} header: {
|
||||
Text(L10n.screenRoomRolesAndPermissionsPermissionsHeader)
|
||||
.compoundListSectionHeader()
|
||||
|
||||
@@ -595,7 +595,8 @@ class MockScreen: Identifiable {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenWithRoomAvatar:
|
||||
@@ -617,7 +618,8 @@ class MockScreen: Identifiable {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenWithEmptyTopic:
|
||||
@@ -640,7 +642,8 @@ class MockScreen: Identifiable {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenWithInvite:
|
||||
@@ -660,7 +663,8 @@ class MockScreen: Identifiable {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomDetailsScreenDmDetails:
|
||||
@@ -681,7 +685,8 @@ class MockScreen: Identifiable {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())))
|
||||
mentionBuilder: MentionBuilder()),
|
||||
appSettings: ServiceLocator.shared.settings))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomEditDetails, .roomEditDetailsReadOnly:
|
||||
@@ -733,6 +738,15 @@ class MockScreen: Identifiable {
|
||||
displayAsUserDefinedRoomSettings: false))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomRolesAndPermissionsFlow:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
navigationStackCoordinator.setRootCoordinator(BlankFormCoordinator())
|
||||
let coordinator = RoomRolesAndPermissionsFlowCoordinator(parameters: .init(roomProxy: RoomProxyMock(with: .init(members: .allMembersAsAdmin)),
|
||||
navigationStackCoordinator: navigationStackCoordinator,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||
retainedState.append(coordinator)
|
||||
coordinator.start()
|
||||
return navigationStackCoordinator
|
||||
case .reportContent:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let coordinator = ReportContentScreenCoordinator(parameters: .init(eventID: "test",
|
||||
|
||||
@@ -73,6 +73,7 @@ enum UITestsScreenIdentifier: String {
|
||||
case roomMemberDetailsIgnoredUser
|
||||
case roomNotificationSettingsDefaultSetting
|
||||
case roomNotificationSettingsCustomSetting
|
||||
case roomRolesAndPermissionsFlow
|
||||
case reportContent
|
||||
case startChat
|
||||
case startChatWithSearchResults
|
||||
|
||||
Reference in New Issue
Block a user