mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Implemented adding the room to the space after selection, and the editableSpace proxied API. Also updated and added tests.
This commit is contained in:
@@ -17100,6 +17100,70 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
|
||||
return joinedParentsChildIDReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - editableSpaces
|
||||
|
||||
var editableSpacesUnderlyingCallsCount = 0
|
||||
var editableSpacesCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return editableSpacesUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = editableSpacesUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
editableSpacesUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
editableSpacesUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var editableSpacesCalled: Bool {
|
||||
return editableSpacesCallsCount > 0
|
||||
}
|
||||
|
||||
var editableSpacesUnderlyingReturnValue: [SpaceServiceRoomProtocol]!
|
||||
var editableSpacesReturnValue: [SpaceServiceRoomProtocol]! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return editableSpacesUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: [SpaceServiceRoomProtocol]? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = editableSpacesUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
editableSpacesUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
editableSpacesUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var editableSpacesClosure: (() async -> [SpaceServiceRoomProtocol])?
|
||||
|
||||
func editableSpaces() async -> [SpaceServiceRoomProtocol] {
|
||||
editableSpacesCallsCount += 1
|
||||
if let editableSpacesClosure = editableSpacesClosure {
|
||||
return await editableSpacesClosure()
|
||||
} else {
|
||||
return editableSpacesReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - addChild
|
||||
|
||||
var addChildToUnderlyingCallsCount = 0
|
||||
|
||||
@@ -111,6 +111,7 @@ extension [SpaceServiceRoomProtocol] {
|
||||
childrenCount: 1,
|
||||
joinedMembersCount: 500,
|
||||
canonicalAlias: "#the-foundation:matrix.org",
|
||||
joinRule: .private,
|
||||
state: .joined)),
|
||||
SpaceServiceRoomMock(.init(id: "space2",
|
||||
name: "The Second Foundation",
|
||||
|
||||
@@ -16,6 +16,7 @@ extension SpaceServiceProxyMock {
|
||||
var topLevelSpaces: [SpaceServiceRoomProtocol] = []
|
||||
var spaceFilters: [SpaceServiceFilter] = []
|
||||
var joinedParentSpaces: [SpaceServiceRoomProtocol] = []
|
||||
var editableSpaces: [SpaceServiceRoomProtocol] = []
|
||||
var spaceRoomLists: [String: SpaceRoomListProxyMock] = [:]
|
||||
var leaveSpaceRooms: [LeaveSpaceRoom] = []
|
||||
}
|
||||
@@ -27,6 +28,7 @@ extension SpaceServiceProxyMock {
|
||||
spaceFilterPublisher = .init(configuration.spaceFilters)
|
||||
|
||||
joinedParentsChildIDReturnValue = .success(configuration.joinedParentSpaces)
|
||||
editableSpacesReturnValue = configuration.editableSpaces
|
||||
spaceRoomListSpaceIDClosure = { spaceID in
|
||||
if let spaceRoomList = configuration.spaceRoomLists[spaceID] {
|
||||
.success(spaceRoomList)
|
||||
|
||||
@@ -31,7 +31,7 @@ struct CreateRoomScreenViewState: BindableState {
|
||||
let isKnockingFeatureEnabled: Bool
|
||||
let canSelectSpace: Bool
|
||||
var aliasLocalPart: String
|
||||
var topLevelSpaces: [SpaceServiceRoomProtocol]
|
||||
var editableSpaces: [SpaceServiceRoomProtocol] = []
|
||||
var bindings: CreateRoomScreenViewStateBindings
|
||||
var avatarMediaInfo: MediaInfo? {
|
||||
didSet {
|
||||
|
||||
@@ -61,11 +61,16 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
|
||||
isKnockingFeatureEnabled: appSettings.knockingEnabled,
|
||||
canSelectSpace: canSelectSpace,
|
||||
aliasLocalPart: roomAliasNameFromRoomDisplayName(roomName: ""),
|
||||
topLevelSpaces: canSelectSpace ? userSession.clientProxy.spaceService.topLevelSpacesPublisher.value : [],
|
||||
bindings: bindings),
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
setupBindings()
|
||||
|
||||
if canSelectSpace {
|
||||
Task {
|
||||
state.editableSpaces = await userSession.clientProxy.spaceService.editableSpaces()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -195,15 +200,6 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
if state.canSelectSpace {
|
||||
userSession
|
||||
.clientProxy
|
||||
.spaceService
|
||||
.topLevelSpacesPublisher
|
||||
.weakAssign(to: \.state.topLevelSpaces, on: self)
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
||||
private func createRoom() async {
|
||||
@@ -277,15 +273,21 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
|
||||
|
||||
var spaceRoomListProxy: SpaceRoomListProxyProtocol?
|
||||
if state.isSpace {
|
||||
switch await userSession.clientProxy.spaceService.spaceRoomList(spaceID: roomProxy.id) {
|
||||
switch await userSession.clientProxy.spaceService.spaceRoomList(spaceID: roomID) {
|
||||
case .success(let value):
|
||||
spaceRoomListProxy = value
|
||||
case .failure:
|
||||
MXLog.error("Failed to get space room list for newly created space with id: \(roomProxy.id)")
|
||||
MXLog.error("Failed to get space room list for newly created space with id: \(roomID)")
|
||||
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||
}
|
||||
}
|
||||
|
||||
if let selectedSpace = state.bindings.selectedSpace,
|
||||
case .failure = await userSession.clientProxy.spaceService.addChild(roomID, to: selectedSpace.id) {
|
||||
MXLog.error("Failed to add the created room with id: \(roomID) to the space with id: \(selectedSpace.id)")
|
||||
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||
}
|
||||
|
||||
actionsSubject.send(.createdRoom(roomProxy, spaceRoomListProxy))
|
||||
case .failure:
|
||||
state.bindings.alertInfo = AlertInfo(id: .failedCreatingRoom,
|
||||
|
||||
@@ -236,8 +236,11 @@ struct CreateRoomScreen: View {
|
||||
} else {
|
||||
ListRow(label: .default(title: L10n.screenCreateRoomSpaceSelectionNoSpaceTitle,
|
||||
description: L10n.screenCreateRoomSpaceSelectionNoSpaceDescription,
|
||||
icon: \.home,
|
||||
iconAlignment: .top),
|
||||
icon: CompoundIcon(\.homeSolid, size: .small, relativeTo: .body)
|
||||
.foregroundColor(.compound.iconPrimary)
|
||||
.background(.compound.bgSubtleSecondary)
|
||||
.scaledFrame(size: 32)
|
||||
.clipAvatar(isSpace: true, size: 32)),
|
||||
kind: .navigationLink {
|
||||
context.showSpaceSelectionSheet = true
|
||||
})
|
||||
@@ -446,6 +449,56 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
||||
viewModel.context.send(viewAction: .updateAliasLocalPart("existing"))
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static let selectedSpaceViewModel = {
|
||||
AppSettings.resetAllSettings()
|
||||
let mockedSpace = SpaceServiceRoomMock(.init(name: "Awesome Space", isSpace: true, joinRule: .private))
|
||||
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
|
||||
return CreateRoomScreenViewModel(isSpace: false,
|
||||
spaceSelectionMode: .selected(mockedSpace),
|
||||
shouldShowCancelButton: false,
|
||||
userSession: userSession,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}()
|
||||
|
||||
static let selectedSpaceWithListViewModel = {
|
||||
let clientProxy = ClientProxyMock(.init(userID: "@userid:example.com"))
|
||||
let spaces = [SpaceServiceRoomProtocol].mockJoinedSpaces2
|
||||
clientProxy.spaceService = SpaceServiceProxyMock(.init(editableSpaces: spaces))
|
||||
let userSession = UserSessionMock(.init(clientProxy: clientProxy))
|
||||
|
||||
let viewModel = CreateRoomScreenViewModel(isSpace: false,
|
||||
spaceSelectionMode: .list,
|
||||
shouldShowCancelButton: false,
|
||||
userSession: userSession,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
|
||||
viewModel.context.selectedSpace = spaces[0]
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static let selectedSpaceWithAskToJoinViewModel = {
|
||||
AppSettings.resetAllSettings()
|
||||
let appSettings = AppSettings()
|
||||
appSettings.knockingEnabled = true
|
||||
|
||||
let mockedSpace = SpaceServiceRoomMock(.init(name: "Awesome Space", isSpace: true, joinRule: .private))
|
||||
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
|
||||
let viewModel = CreateRoomScreenViewModel(isSpace: false,
|
||||
spaceSelectionMode: .selected(mockedSpace),
|
||||
shouldShowCancelButton: false,
|
||||
userSession: userSession,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: appSettings)
|
||||
|
||||
viewModel.context.selectedAccessType = .askToJoinWithSpaceMembers
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
@@ -491,5 +544,20 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
||||
}
|
||||
.snapshotPreferences(expect: publicRoomExistingAliasViewModel.context.$viewState.map { !$0.aliasErrors.isEmpty })
|
||||
.previewDisplayName("Create Public Room, existing alias")
|
||||
|
||||
NavigationStack {
|
||||
CreateRoomScreen(context: selectedSpaceViewModel.context)
|
||||
}
|
||||
.previewDisplayName("Create Room with already selected Space")
|
||||
|
||||
NavigationStack {
|
||||
CreateRoomScreen(context: selectedSpaceWithListViewModel.context)
|
||||
}
|
||||
.previewDisplayName("Create Room with a selected Space from the list")
|
||||
|
||||
NavigationStack {
|
||||
CreateRoomScreen(context: selectedSpaceWithAskToJoinViewModel.context)
|
||||
}
|
||||
.previewDisplayName("Create Knockable Room with already selected Space")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,16 @@ struct CreateRoomSpaceSelectionSheet: View {
|
||||
Section {
|
||||
ListRow(label: .default(title: L10n.screenCreateRoomSpaceSelectionNoSpaceTitle,
|
||||
description: L10n.screenCreateRoomSpaceSelectionNoSpaceDescription,
|
||||
icon: \.home),
|
||||
icon: CompoundIcon(\.homeSolid, size: .small, relativeTo: .body)
|
||||
.foregroundColor(.compound.iconPrimary)
|
||||
.background(.compound.bgSubtleSecondary)
|
||||
.scaledFrame(size: 32)
|
||||
.clipAvatar(isSpace: true, size: 32)),
|
||||
kind: .selection(isSelected: context.selectedSpace == nil) {
|
||||
context.selectedSpace = nil
|
||||
dismiss()
|
||||
})
|
||||
ForEach(context.viewState.topLevelSpaces, id: \.id) { space in
|
||||
ForEach(context.viewState.editableSpaces, id: \.id) { space in
|
||||
ListRow(label: .avatar(title: space.name,
|
||||
description: space.canonicalAlias,
|
||||
icon: RoomAvatarImage(avatar: space.avatar,
|
||||
@@ -66,7 +70,7 @@ struct CreateRoomSpaceSelectionSheet: View {
|
||||
struct CreateRoomSpaceSelectionSheet_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = {
|
||||
let clientProxy = ClientProxyMock(.init(userID: "@userid:example.com"))
|
||||
clientProxy.spaceService = SpaceServiceProxyMock(.init(topLevelSpaces: .mockJoinedSpaces2))
|
||||
clientProxy.spaceService = SpaceServiceProxyMock(.init(editableSpaces: .mockJoinedSpaces2))
|
||||
let userSession = UserSessionMock(.init(clientProxy: clientProxy))
|
||||
|
||||
return CreateRoomScreenViewModel(isSpace: false,
|
||||
@@ -80,5 +84,6 @@ struct CreateRoomSpaceSelectionSheet_Previews: PreviewProvider, TestablePreview
|
||||
|
||||
static var previews: some View {
|
||||
CreateRoomSpaceSelectionSheet(context: viewModel.context)
|
||||
.snapshotPreferences(expect: viewModel.context.$viewState.map { $0.editableSpaces.count > 0 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,10 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func editableSpaces() async -> [SpaceServiceRoomProtocol] {
|
||||
await spaceService.editableSpaces().map(SpaceServiceRoom.init)
|
||||
}
|
||||
|
||||
func addChild(_ childID: String, to spaceID: String) async -> Result<Void, SpaceServiceProxyError> {
|
||||
do {
|
||||
return try await .success(spaceService.addChildToSpace(childId: childID, spaceId: spaceID))
|
||||
@@ -94,7 +98,7 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol {
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func handleSpaceListUpdates(_ updates: [SpaceListUpdate]) {
|
||||
|
||||
@@ -52,6 +52,8 @@ protocol SpaceServiceProxyProtocol {
|
||||
func leaveSpace(spaceID: String) async -> Result<LeaveSpaceHandleProxy, SpaceServiceProxyError>
|
||||
/// Returns all the parent spaces of a child that user has joined.
|
||||
func joinedParents(childID: String) async -> Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError>
|
||||
/// Returns all the parent spaces that can be edited by the user
|
||||
func editableSpaces() async -> [SpaceServiceRoomProtocol]
|
||||
|
||||
/// Adds a room (or space) as a child of another space.
|
||||
func addChild(_ childID: String, to spaceID: String) async -> Result<Void, SpaceServiceProxyError>
|
||||
|
||||
Reference in New Issue
Block a user