implemented the logic that displays the space selection CTA

This commit is contained in:
Mauro Romito
2026-01-19 20:18:51 +01:00
committed by Mauro
parent 204fa5b0ca
commit 7f66b694b1
12 changed files with 134 additions and 51 deletions
@@ -193,6 +193,7 @@ class StartChatFlowCoordinator: FlowCoordinatorProtocol {
private func presentCreateRoomScreen(isSpace: Bool, isRoot: Bool) {
let createParameters = CreateRoomScreenCoordinatorParameters(isSpace: isSpace,
spaceSelectionMode: !isSpace && flowParameters.appSettings.createSpaceEnabled ? .list : nil,
shouldShowCancelButton: isRoot,
userSession: flowParameters.userSession,
userIndicatorController: flowParameters.userIndicatorController,
+3 -1
View File
@@ -156,13 +156,15 @@ enum RoomAvatarSizeOnScreen {
case spaceAddRooms
case spaceAddRoomsSelected
case completionSuggestions
case createRoomSelectSpace
var value: CGFloat {
switch self {
case .chats, .spaces, .spaceSettings:
return 52
case .timeline, .leaveSpace, .roomDirectorySearch,
.completionSuggestions, .authorizedSpaces, .spaceFilters:
.completionSuggestions, .authorizedSpaces,.createRoomSelectSpace,
.spaceFilters:
return 32
case .notificationSettings:
return 30
@@ -32,6 +32,7 @@ enum TestablePreviewsDictionary {
"CompletionSuggestion_Previews" : CompletionSuggestion_Previews.self,
"ComposerToolbar_Previews" : ComposerToolbar_Previews.self,
"CopyTextButton_Previews" : CopyTextButton_Previews.self,
"CreateRoomSpaceSelectionSheet_Previews" : CreateRoomSpaceSelectionSheet_Previews.self,
"CreateRoom_Previews" : CreateRoom_Previews.self,
"DeactivateAccountScreen_Previews" : DeactivateAccountScreen_Previews.self,
"DeclineAndBlockScreen_Previews" : DeclineAndBlockScreen_Previews.self,
@@ -11,6 +11,7 @@ import SwiftUI
struct CreateRoomScreenCoordinatorParameters {
let isSpace: Bool
let spaceSelectionMode: CreateRoomScreenSpaceSelectionMode?
let shouldShowCancelButton: Bool
let userSession: UserSessionProtocol
let userIndicatorController: UserIndicatorControllerProtocol
@@ -35,6 +36,7 @@ final class CreateRoomScreenCoordinator: CoordinatorProtocol {
init(parameters: CreateRoomScreenCoordinatorParameters) {
viewModel = CreateRoomScreenViewModel(isSpace: parameters.isSpace,
spaceSelectionMode: parameters.spaceSelectionMode,
shouldShowCancelButton: parameters.shouldShowCancelButton,
userSession: parameters.userSession,
analytics: parameters.analytics,
@@ -31,6 +31,7 @@ struct CreateRoomScreenViewState: BindableState {
let isKnockingFeatureEnabled: Bool
let canSelectSpace: Bool
var aliasLocalPart: String
var topLevelSpaces: [SpaceServiceRoomProtocol]
var bindings: CreateRoomScreenViewStateBindings
var avatarMediaInfo: MediaInfo? {
didSet {
@@ -59,14 +60,12 @@ struct CreateRoomScreenViewState: BindableState {
nil
}
}
var selectedSpace: SpaceServiceRoomProtocol?
var availableAccessTypes: [CreateRoomScreenAccessType] {
var availableAccessTypes: [CreateRoomScreenAccessType] = []
if isSpace {
availableAccessTypes = [.public]
} else if let selectedSpace, selectedSpace.joinRule != .public {
} else if let selectedSpace = bindings.selectedSpace, selectedSpace.joinRule != .public {
availableAccessTypes = [.spaceMembers]
if isKnockingFeatureEnabled {
availableAccessTypes.append(.askToJoinWithSpaceMembers)
@@ -86,9 +85,9 @@ struct CreateRoomScreenViewState: BindableState {
case .public:
return .public
case .spaceMembers:
return .spaceMembers(spaceID: selectedSpace?.id ?? "")
return .spaceMembers(spaceID: bindings.selectedSpace?.id ?? "")
case .askToJoinWithSpaceMembers:
return .askToJoinWithSpaceMembers(spaceID: selectedSpace?.id ?? "")
return .askToJoinWithSpaceMembers(spaceID: bindings.selectedSpace?.id ?? "")
case .askToJoin:
return .askToJoin
case .private:
@@ -100,7 +99,10 @@ struct CreateRoomScreenViewState: BindableState {
struct CreateRoomScreenViewStateBindings {
var roomTopic: String
var selectedAccessType: CreateRoomScreenAccessType
var selectedSpace: SpaceServiceRoomProtocol?
var showAttachmentConfirmationDialog = false
var showSpaceSelectionSheet = false
/// Information describing the currently displayed alert.
var alertInfo: AlertInfo<CreateRoomScreenErrorType>?
@@ -139,3 +141,8 @@ enum CreateRoomScreenAccessType {
case askToJoin
case `private`
}
enum CreateRoomScreenSpaceSelectionMode {
case list
case selected(SpaceServiceRoomProtocol)
}
@@ -17,6 +17,7 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
private let mediaUploadingPreprocessor: MediaUploadingPreprocessor
private let analytics: AnalyticsService
private let userIndicatorController: UserIndicatorControllerProtocol
private var syncNameAndAlias = true
@CancellableTask private var checkAliasAvailabilityTask: Task<Void, Never>?
@@ -27,6 +28,7 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
}
init(isSpace: Bool,
spaceSelectionMode: CreateRoomScreenSpaceSelectionMode?,
shouldShowCancelButton: Bool,
userSession: UserSessionProtocol,
analytics: AnalyticsService,
@@ -37,16 +39,29 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
self.analytics = analytics
self.userIndicatorController = userIndicatorController
var selectedSpace: SpaceServiceRoomProtocol?
var canSelectSpace = false
switch spaceSelectionMode {
case .list:
canSelectSpace = true
case .selected(let value):
selectedSpace = value
case .none:
break
}
let bindings = CreateRoomScreenViewStateBindings(roomTopic: "",
selectedAccessType: .private)
selectedAccessType: .private,
selectedSpace: selectedSpace)
super.init(initialViewState: CreateRoomScreenViewState(isSpace: isSpace,
shouldShowCancelButton: shouldShowCancelButton,
roomName: "",
serverName: userSession.clientProxy.userIDServerName ?? "",
isKnockingFeatureEnabled: appSettings.knockingEnabled,
canSelectSpace: isSpace ? false : appSettings.createSpaceEnabled,
canSelectSpace: canSelectSpace,
aliasLocalPart: roomAliasNameFromRoomDisplayName(roomName: ""),
topLevelSpaces: canSelectSpace ? userSession.clientProxy.spaceService.topLevelSpacesPublisher.value : [],
bindings: bindings),
mediaProvider: userSession.mediaProvider)
@@ -180,6 +195,15 @@ 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 {
@@ -55,6 +55,9 @@ struct CreateRoomScreen: View {
.toolbar { toolbar }
.alert(item: $context.alertInfo)
.shouldScrollOnKeyboardDidShow(focus == .alias, to: Focus.alias)
.sheet(isPresented: $context.showSpaceSelectionSheet) {
CreateRoomSpaceSelectionSheet(context: context)
}
}
private var nameTextFieldShape: AnyShape {
@@ -184,7 +187,7 @@ struct CreateRoomScreen: View {
Section {
ForEach(context.viewState.availableAccessTypes, id: \.self) { accessType in
CreateRoomAccessRow(access: accessType,
spaceName: context.viewState.selectedSpace?.name ?? "",
spaceName: context.selectedSpace?.name ?? "",
isSelected: context.selectedAccessType == accessType) {
context.selectedAccessType = accessType
}
@@ -221,7 +224,21 @@ struct CreateRoomScreen: View {
private var selectSpaceSection: some View {
Section {
EmptyView()
if let selectedSpace = context.selectedSpace {
ListRow(label: .avatar(title: selectedSpace.name,
description: selectedSpace.canonicalAlias,
icon: RoomAvatarImage(avatar: selectedSpace.avatar,
avatarSize: .room(on: .createRoomSelectSpace),
mediaProvider: context.mediaProvider)),
kind: .navigationLink {
context.showSpaceSelectionSheet = true
})
} else {
ListRow(label: .default(title: "Test", icon: \.home),
kind: .navigationLink {
context.showSpaceSelectionSheet = true
})
}
} header: {
Text(L10n.commonSpace)
.compoundListSectionHeader()
@@ -317,6 +334,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
return CreateRoomScreenViewModel(isSpace: false,
spaceSelectionMode: .list,
shouldShowCancelButton: false,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -328,6 +346,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
let viewModel = CreateRoomScreenViewModel(isSpace: false,
spaceSelectionMode: .list,
shouldShowCancelButton: false,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -341,6 +360,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
return CreateRoomScreenViewModel(isSpace: true,
spaceSelectionMode: nil,
shouldShowCancelButton: true,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -352,6 +372,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
let viewModel = CreateRoomScreenViewModel(isSpace: true,
spaceSelectionMode: nil,
shouldShowCancelButton: true,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -365,6 +386,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userIDServerName: "example.org", userID: "@userid:example.com"))))
let viewModel = CreateRoomScreenViewModel(isSpace: false,
spaceSelectionMode: .list,
shouldShowCancelButton: false,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -380,6 +402,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
appSettings.knockingEnabled = true
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userIDServerName: "example.org", userID: "@userid:example.com"))))
let viewModel = CreateRoomScreenViewModel(isSpace: false,
spaceSelectionMode: .list,
shouldShowCancelButton: false,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -393,6 +416,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userIDServerName: "example.org", userID: "@userid:example.com"))))
let viewModel = CreateRoomScreenViewModel(isSpace: false,
spaceSelectionMode: .list,
shouldShowCancelButton: false,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -409,6 +433,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
clientProxy.isAliasAvailableReturnValue = .success(false)
let userSession = UserSessionMock(.init(clientProxy: clientProxy))
let viewModel = CreateRoomScreenViewModel(isSpace: false,
spaceSelectionMode: .list,
shouldShowCancelButton: false,
userSession: userSession,
analytics: ServiceLocator.shared.analytics,
@@ -0,0 +1,22 @@
//
// Copyright 2026 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 SwiftUI
struct CreateRoomSpaceSelectionSheet: View {
@ObservedObject var context: CreateRoomScreenViewModel.Context
var body: some View {
EmptyView()
}
}
struct CreateRoomSpaceSelectionSheet_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
EmptyView()
}
}