mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 20:09:04 +00:00
implemented the logic to transfer ownership from a space
This commit is contained in:
@@ -349,6 +349,9 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
stateMachine.tryEvent(.addRooms)
|
stateMachine.tryEvent(.addRooms)
|
||||||
case .displayCreateChildRoomFlow(let space):
|
case .displayCreateChildRoomFlow(let space):
|
||||||
stateMachine.tryEvent(.startCreateChildRoomFlow, userInfo: space)
|
stateMachine.tryEvent(.startCreateChildRoomFlow, userInfo: space)
|
||||||
|
case .displayTransferOwnership(roomProxy: let roomProxy):
|
||||||
|
// TODO: Implement
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ extension LeaveSpaceHandleSDKMock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension [LeaveSpaceRoom] {
|
extension [LeaveSpaceRoom] {
|
||||||
static func mockRoomsWithSpace(spaceServiceRoom: SpaceServiceRoom, isLastOwner: Bool) -> [LeaveSpaceRoom] {
|
static func mockRoomsWithSpace(spaceServiceRoom: SpaceServiceRoom, isLastOwner: Bool, areCreatorsPrivileged: Bool) -> [LeaveSpaceRoom] {
|
||||||
mockRooms + mockSingleSpace(spaceServiceRoom: spaceServiceRoom, isLastOwner: isLastOwner)
|
mockRooms + mockSingleSpace(spaceServiceRoom: spaceServiceRoom, isLastOwner: isLastOwner, areCreatorsPrivileged: areCreatorsPrivileged)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func mockSingleSpace(spaceServiceRoom: SpaceServiceRoom, isLastOwner: Bool) -> [LeaveSpaceRoom] {
|
static func mockSingleSpace(spaceServiceRoom: SpaceServiceRoom, isLastOwner: Bool, areCreatorsPrivileged: Bool) -> [LeaveSpaceRoom] {
|
||||||
[LeaveSpaceRoom(spaceRoom: SpaceRoom(id: spaceServiceRoom.id,
|
[LeaveSpaceRoom(spaceRoom: SpaceRoom(id: spaceServiceRoom.id,
|
||||||
name: spaceServiceRoom.name,
|
name: spaceServiceRoom.name,
|
||||||
avatarURL: spaceServiceRoom.avatarURL,
|
avatarURL: spaceServiceRoom.avatarURL,
|
||||||
@@ -35,7 +35,7 @@ extension [LeaveSpaceRoom] {
|
|||||||
memberCount: UInt64(spaceServiceRoom.joinedMembersCount),
|
memberCount: UInt64(spaceServiceRoom.joinedMembersCount),
|
||||||
joinRule: spaceServiceRoom.joinRule),
|
joinRule: spaceServiceRoom.joinRule),
|
||||||
isLastOwner: isLastOwner,
|
isLastOwner: isLastOwner,
|
||||||
areCreatorsPrivileged: false)]
|
areCreatorsPrivileged: areCreatorsPrivileged)]
|
||||||
}
|
}
|
||||||
|
|
||||||
static var mockNeedNewOwnerRooms: [LeaveSpaceRoom] {
|
static var mockNeedNewOwnerRooms: [LeaveSpaceRoom] {
|
||||||
|
|||||||
@@ -93,15 +93,15 @@ struct RoomChangeRolesScreen: View {
|
|||||||
@ToolbarContentBuilder
|
@ToolbarContentBuilder
|
||||||
private var toolbar: some ToolbarContent {
|
private var toolbar: some ToolbarContent {
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
Button(L10n.actionSave) {
|
ToolbarButton(role: .save) {
|
||||||
context.send(viewAction: .save)
|
context.send(viewAction: .save)
|
||||||
}
|
}
|
||||||
.disabled(!context.viewState.hasChanges)
|
.disabled(!context.viewState.hasChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
if context.viewState.hasChanges {
|
if context.viewState.mode == .owner {
|
||||||
ToolbarItem(placement: .cancellationAction) {
|
ToolbarItem(placement: .cancellationAction) {
|
||||||
Button(L10n.actionCancel) {
|
ToolbarButton(role: .cancel) {
|
||||||
context.send(viewAction: .cancel)
|
context.send(viewAction: .cancel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,6 +226,9 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
case .didLeaveSpace:
|
case .didLeaveSpace:
|
||||||
state.bindings.leaveSpaceViewModel = nil
|
state.bindings.leaveSpaceViewModel = nil
|
||||||
actionsSubject.send(.leftRoom)
|
actionsSubject.send(.leftRoom)
|
||||||
|
case .presentTransferOwnership:
|
||||||
|
state.bindings.leaveSpaceViewModel = nil
|
||||||
|
actionsSubject.send(.transferOwnership)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ enum LeaveSpaceViewAction {
|
|||||||
case selectAll
|
case selectAll
|
||||||
case toggleRoom(roomID: String)
|
case toggleRoom(roomID: String)
|
||||||
case rolesAndPermissions
|
case rolesAndPermissions
|
||||||
|
case transferOwnership
|
||||||
case cancel
|
case cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,5 +45,6 @@ struct LeaveSpaceViewState: BindableState {
|
|||||||
enum LeaveSpaceViewModelAction {
|
enum LeaveSpaceViewModelAction {
|
||||||
case didLeaveSpace
|
case didLeaveSpace
|
||||||
case presentRolesAndPermissions
|
case presentRolesAndPermissions
|
||||||
|
case presentTransferOwnership
|
||||||
case didCancel
|
case didCancel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ class LeaveSpaceViewModel: LeaveSpaceViewModelType {
|
|||||||
withTransaction(\.disablesAnimations, true) { // The button is adding an unwanted animation.
|
withTransaction(\.disablesAnimations, true) { // The button is adding an unwanted animation.
|
||||||
state.leaveHandle.toggleRoom(roomID: roomID)
|
state.leaveHandle.toggleRoom(roomID: roomID)
|
||||||
}
|
}
|
||||||
|
case .transferOwnership:
|
||||||
|
actionsSubject.send(.presentTransferOwnership)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ struct LeaveSpaceView: View {
|
|||||||
Section {
|
Section {
|
||||||
ForEach(context.viewState.leaveHandle.rooms, id: \.spaceServiceRoom.id) { room in
|
ForEach(context.viewState.leaveHandle.rooms, id: \.spaceServiceRoom.id) { room in
|
||||||
LeaveSpaceRoomDetailsCell(room: room,
|
LeaveSpaceRoomDetailsCell(room: room,
|
||||||
hideSelection: context.viewState.leaveHandle.mode == .roomsNeedNewOwner,
|
hideSelection: !context.viewState.leaveHandle.canLeave,
|
||||||
mediaProvider: context.mediaProvider) {
|
mediaProvider: context.mediaProvider) {
|
||||||
context.send(viewAction: .toggleRoom(roomID: room.spaceServiceRoom.id))
|
context.send(viewAction: .toggleRoom(roomID: room.spaceServiceRoom.id))
|
||||||
}
|
}
|
||||||
@@ -90,20 +90,32 @@ struct LeaveSpaceView: View {
|
|||||||
|
|
||||||
var buttons: some View {
|
var buttons: some View {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
if context.viewState.leaveHandle.canLeave {
|
switch context.viewState.leaveHandle.mode {
|
||||||
|
case .spaceNeedsNewOwner(let useTransferOwnershipFlow):
|
||||||
|
if context.viewState.canEditRolesAndPermissions {
|
||||||
|
if useTransferOwnershipFlow {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
context.send(viewAction: .transferOwnership)
|
||||||
|
} label: {
|
||||||
|
Label(L10n.actionGoToRolesAndPermissions, icon: \.settings)
|
||||||
|
}
|
||||||
|
.buttonStyle(.compound(.primary))
|
||||||
|
} else {
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .rolesAndPermissions)
|
||||||
|
} label: {
|
||||||
|
Label(L10n.actionGoToRolesAndPermissions, icon: \.settings)
|
||||||
|
}
|
||||||
|
.buttonStyle(.compound(.primary))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
context.send(viewAction: .confirmLeaveSpace)
|
context.send(viewAction: .confirmLeaveSpace)
|
||||||
} label: {
|
} label: {
|
||||||
Label(context.viewState.confirmationTitle, icon: \.leave)
|
Label(context.viewState.confirmationTitle, icon: \.leave)
|
||||||
}
|
}
|
||||||
.buttonStyle(.compound(.primary))
|
.buttonStyle(.compound(.primary))
|
||||||
} else if context.viewState.canEditRolesAndPermissions {
|
|
||||||
Button {
|
|
||||||
context.send(viewAction: .rolesAndPermissions)
|
|
||||||
} label: {
|
|
||||||
Label(L10n.actionGoToRolesAndPermissions, icon: \.settings)
|
|
||||||
}
|
|
||||||
.buttonStyle(.compound(.primary))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(L10n.actionCancel, action: dismiss.callAsFunction)
|
Button(L10n.actionCancel, action: dismiss.callAsFunction)
|
||||||
@@ -123,7 +135,8 @@ struct LeaveSpaceView_Previews: PreviewProvider, TestablePreview {
|
|||||||
static let manyViewModel = makeViewModel(mode: .manyRooms)
|
static let manyViewModel = makeViewModel(mode: .manyRooms)
|
||||||
static let onlyAdminViewModel = makeViewModel(mode: .roomsNeedNewOwner)
|
static let onlyAdminViewModel = makeViewModel(mode: .roomsNeedNewOwner)
|
||||||
static let noRoomsViewModel = makeViewModel(mode: .noRooms)
|
static let noRoomsViewModel = makeViewModel(mode: .noRooms)
|
||||||
static let lastAdminViewModel = makeViewModel(mode: .spaceNeedsNewOwner)
|
static let lastAdminViewModel = makeViewModel(mode: .spaceNeedsNewOwner(useTransferOwnershipFlow: false))
|
||||||
|
static let lastOwnerViewModel = makeViewModel(mode: .spaceNeedsNewOwner(useTransferOwnershipFlow: true))
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
LeaveSpaceView(context: manyViewModel.context)
|
LeaveSpaceView(context: manyViewModel.context)
|
||||||
@@ -134,6 +147,8 @@ struct LeaveSpaceView_Previews: PreviewProvider, TestablePreview {
|
|||||||
.previewDisplayName("No Rooms")
|
.previewDisplayName("No Rooms")
|
||||||
LeaveSpaceView(context: lastAdminViewModel.context)
|
LeaveSpaceView(context: lastAdminViewModel.context)
|
||||||
.previewDisplayName("Last Space Admin")
|
.previewDisplayName("Last Space Admin")
|
||||||
|
LeaveSpaceView(context: lastOwnerViewModel.context)
|
||||||
|
.previewDisplayName("Last Space Owner")
|
||||||
}
|
}
|
||||||
|
|
||||||
static let spaceServiceRoom = SpaceServiceRoom.mock(id: "!eng-space:matrix.org",
|
static let spaceServiceRoom = SpaceServiceRoom.mock(id: "!eng-space:matrix.org",
|
||||||
@@ -149,8 +164,12 @@ struct LeaveSpaceView_Previews: PreviewProvider, TestablePreview {
|
|||||||
let rooms: [LeaveSpaceRoom] = switch mode {
|
let rooms: [LeaveSpaceRoom] = switch mode {
|
||||||
case .manyRooms: .mockRooms
|
case .manyRooms: .mockRooms
|
||||||
case .roomsNeedNewOwner: .mockNeedNewOwnerRooms
|
case .roomsNeedNewOwner: .mockNeedNewOwnerRooms
|
||||||
case .noRooms: .mockSingleSpace(spaceServiceRoom: spaceServiceRoom, isLastOwner: false)
|
case .noRooms: .mockSingleSpace(spaceServiceRoom: spaceServiceRoom,
|
||||||
case .spaceNeedsNewOwner: .mockRoomsWithSpace(spaceServiceRoom: spaceServiceRoom, isLastOwner: true)
|
isLastOwner: false,
|
||||||
|
areCreatorsPrivileged: false)
|
||||||
|
case .spaceNeedsNewOwner(let useTransferOwnershipFlow): .mockRoomsWithSpace(spaceServiceRoom: spaceServiceRoom,
|
||||||
|
isLastOwner: true,
|
||||||
|
areCreatorsPrivileged: useTransferOwnershipFlow)
|
||||||
}
|
}
|
||||||
|
|
||||||
let leaveHandle = LeaveSpaceHandleProxy(spaceID: spaceServiceRoom.id,
|
let leaveHandle = LeaveSpaceHandleProxy(spaceID: spaceServiceRoom.id,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ enum SpaceScreenCoordinatorAction {
|
|||||||
case displayMembers(roomProxy: JoinedRoomProxyProtocol)
|
case displayMembers(roomProxy: JoinedRoomProxyProtocol)
|
||||||
case displaySpaceSettings(roomProxy: JoinedRoomProxyProtocol)
|
case displaySpaceSettings(roomProxy: JoinedRoomProxyProtocol)
|
||||||
case displayRolesAndPermissions(roomProxy: JoinedRoomProxyProtocol)
|
case displayRolesAndPermissions(roomProxy: JoinedRoomProxyProtocol)
|
||||||
|
case displayTransferOwnership(roomProxy: JoinedRoomProxyProtocol)
|
||||||
case addExistingChildren
|
case addExistingChildren
|
||||||
case displayCreateChildRoomFlow(space: SpaceServiceRoom)
|
case displayCreateChildRoomFlow(space: SpaceServiceRoom)
|
||||||
}
|
}
|
||||||
@@ -78,6 +79,8 @@ final class SpaceScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.addExistingChildren)
|
actionsSubject.send(.addExistingChildren)
|
||||||
case .displayCreateChildRoomFlow(let space):
|
case .displayCreateChildRoomFlow(let space):
|
||||||
actionsSubject.send(.displayCreateChildRoomFlow(space: space))
|
actionsSubject.send(.displayCreateChildRoomFlow(space: space))
|
||||||
|
case .presentTransferOwnership(roomProxy: let roomProxy):
|
||||||
|
actionsSubject.send(.displayTransferOwnership(roomProxy: roomProxy))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ enum SpaceScreenViewModelAction {
|
|||||||
case selectRoom(roomID: String)
|
case selectRoom(roomID: String)
|
||||||
case leftSpace
|
case leftSpace
|
||||||
case presentRolesAndPermissions(roomProxy: JoinedRoomProxyProtocol)
|
case presentRolesAndPermissions(roomProxy: JoinedRoomProxyProtocol)
|
||||||
|
case presentTransferOwnership(roomProxy: JoinedRoomProxyProtocol)
|
||||||
case displayMembers(roomProxy: JoinedRoomProxyProtocol)
|
case displayMembers(roomProxy: JoinedRoomProxyProtocol)
|
||||||
case displaySpaceSettings(roomProxy: JoinedRoomProxyProtocol)
|
case displaySpaceSettings(roomProxy: JoinedRoomProxyProtocol)
|
||||||
case addExistingChildren
|
case addExistingChildren
|
||||||
|
|||||||
@@ -261,6 +261,12 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
|
|||||||
case .didLeaveSpace:
|
case .didLeaveSpace:
|
||||||
state.bindings.leaveSpaceViewModel = nil
|
state.bindings.leaveSpaceViewModel = nil
|
||||||
actionsSubject.send(.leftSpace)
|
actionsSubject.send(.leftSpace)
|
||||||
|
case .presentTransferOwnership:
|
||||||
|
guard let roomProxy = state.roomProxy else {
|
||||||
|
fatalError("The space screen should always have a room proxy")
|
||||||
|
}
|
||||||
|
state.bindings.leaveSpaceViewModel = nil
|
||||||
|
actionsSubject.send(.presentTransferOwnership(roomProxy: roomProxy))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -13,13 +13,24 @@ final class LeaveSpaceHandleProxy {
|
|||||||
let id: String
|
let id: String
|
||||||
var rooms: [LeaveSpaceRoomDetails]
|
var rooms: [LeaveSpaceRoomDetails]
|
||||||
|
|
||||||
enum Mode { case manyRooms, roomsNeedNewOwner, noRooms, spaceNeedsNewOwner }
|
enum Mode: Equatable {
|
||||||
|
case manyRooms
|
||||||
|
case roomsNeedNewOwner
|
||||||
|
case noRooms
|
||||||
|
case spaceNeedsNewOwner(useTransferOwnershipFlow: Bool)
|
||||||
|
}
|
||||||
|
|
||||||
let mode: Mode
|
let mode: Mode
|
||||||
|
|
||||||
private let leaveHandle: LeaveSpaceHandleProtocol
|
private let leaveHandle: LeaveSpaceHandleProtocol
|
||||||
|
|
||||||
var canLeave: Bool {
|
var canLeave: Bool {
|
||||||
mode != .spaceNeedsNewOwner
|
switch mode {
|
||||||
|
case .spaceNeedsNewOwner:
|
||||||
|
false
|
||||||
|
default:
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedCount: Int {
|
var selectedCount: Int {
|
||||||
@@ -47,7 +58,7 @@ final class LeaveSpaceHandleProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mode = if let space, space.isLastOwner, space.spaceRoom.numJoinedMembers > 1 {
|
mode = if let space, space.isLastOwner, space.spaceRoom.numJoinedMembers > 1 {
|
||||||
.spaceNeedsNewOwner
|
.spaceNeedsNewOwner(useTransferOwnershipFlow: space.areCreatorsPrivileged)
|
||||||
} else if self.rooms.isEmpty {
|
} else if self.rooms.isEmpty {
|
||||||
.noRooms
|
.noRooms
|
||||||
} else if self.rooms.count(where: { $0.canLeave }) == 0 {
|
} else if self.rooms.count(where: { $0.canLeave }) == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user