Space Settings: Leave Room (#4700)

* Implementation for all navigations inside the space settings aside the left space action

# Conflicts:
#	ElementX/Sources/FlowCoordinators/SpaceSettingsFlowCoordinator.swift

* refactored the leave space view to use its own view model

# Conflicts:
#	ElementX.xcodeproj/project.pbxproj

* implemented the leave space view model also in the settings screen, and corrected some tests

* reusing the details coordinator for the space settings screen

* leave space from settings implemented

* fix project

* minor pr fixes

* code improvements
This commit is contained in:
Mauro
2025-11-07 12:11:21 +01:00
committed by GitHub
parent 8974a4584a
commit 096e2d1713
22 changed files with 407 additions and 277 deletions
@@ -0,0 +1,79 @@
//
// Copyright 2025 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
import SwiftUI
typealias LeaveSpaceViewModelType = StateStoreViewModelV2<LeaveSpaceViewState, LeaveSpaceViewAction>
class LeaveSpaceViewModel: LeaveSpaceViewModelType {
let actionsSubject = PassthroughSubject<LeaveSpaceViewModelAction, Never>()
var actions: AnyPublisher<LeaveSpaceViewModelAction, Never> { actionsSubject.eraseToAnyPublisher() }
private let userIndicatorController: UserIndicatorControllerProtocol
private let mediaProvider: MediaProviderProtocol
init(spaceName: String, canEditRolesAndPermissions: Bool, leaveHandle: LeaveSpaceHandleProxy, userIndicatorController: UserIndicatorControllerProtocol, mediaProvider: MediaProviderProtocol) {
self.userIndicatorController = userIndicatorController
self.mediaProvider = mediaProvider
super.init(initialViewState: LeaveSpaceViewState(spaceName: spaceName, canEditRolesAndPermissions: canEditRolesAndPermissions, leaveHandle: leaveHandle), mediaProvider: mediaProvider)
}
override func process(viewAction: LeaveSpaceViewAction) {
switch viewAction {
case .confirmLeaveSpace:
Task { await confirmLeaveSpace() }
case .rolesAndPermissions:
actionsSubject.send(.presentRolesAndPermissions)
case .cancel:
actionsSubject.send(.didCancel)
case .deselectAll:
state.leaveHandle.deselectAll()
case .selectAll:
state.leaveHandle.selectAll()
case .toggleRoom(let roomID):
withTransaction(\.disablesAnimations, true) { // The button is adding an unwanted animation.
state.leaveHandle.toggleRoom(roomID: roomID)
}
}
}
private func confirmLeaveSpace() async {
showLeavingIndicator()
defer { hideLeavingIndicator() }
switch await state.leaveHandle.leave() {
case .success:
actionsSubject.send(.didLeaveSpace)
case .failure:
showFailureIndicator()
}
}
private static var leavingIndicatorID: String { "\(Self.self)-Leaving" }
private static var failureIndicatorID: String { "\(Self.self)-Failure" }
private func showLeavingIndicator() {
userIndicatorController.submitIndicator(UserIndicator(id: Self.leavingIndicatorID,
type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false),
title: L10n.commonLeavingSpace))
}
private func hideLeavingIndicator() {
userIndicatorController.retractIndicatorWithId(Self.leavingIndicatorID)
}
private func showFailureIndicator() {
userIndicatorController.submitIndicator(UserIndicator(id: Self.failureIndicatorID,
type: .toast,
title: L10n.errorUnknown,
iconName: "xmark"))
}
}
extension LeaveSpaceViewModel: Identifiable {
var id: String { state.leaveHandle.id }
}