started implementing the logic behind the access type and the creation parameters

This commit is contained in:
Mauro Romito
2026-01-19 18:21:01 +01:00
committed by Mauro
parent ed892fee94
commit 4fba0d1ce6
5 changed files with 109 additions and 18 deletions

View File

@@ -29,6 +29,7 @@ struct CreateRoomScreenViewState: BindableState {
var roomName: String
let serverName: String
let isKnockingFeatureEnabled: Bool
let canSelectSpace: Bool
var aliasLocalPart: String
var bindings: CreateRoomScreenViewStateBindings
var avatarMediaInfo: MediaInfo? {
@@ -59,18 +60,46 @@ struct CreateRoomScreenViewState: BindableState {
}
}
var availableAccessTypes: [CreateRoomAccessType] {
var availableTypes = CreateRoomAccessType.allCases
if isSpace || !isKnockingFeatureEnabled {
availableTypes.removeAll { $0 == .askToJoin }
var selectedSpace: SpaceServiceRoomProtocol?
var availableAccessTypes: [CreateRoomScreenAccessType] {
var availableAccessTypes: [CreateRoomScreenAccessType] = []
if isSpace {
availableAccessTypes = [.public]
} else if let selectedSpace, selectedSpace.joinRule != .public {
availableAccessTypes = [.spaceMembers]
if isKnockingFeatureEnabled {
availableAccessTypes.append(.askToJoinWithSpaceMembers)
}
} else {
availableAccessTypes = [.public]
if isKnockingFeatureEnabled {
availableAccessTypes.append(.askToJoin)
}
}
availableAccessTypes.append(.private)
return availableAccessTypes
}
var roomAccessType: CreateRoomAccessType {
switch bindings.selectedAccessType {
case .public:
return .public
case .spaceMembers:
return .spaceMembers(spaceID: selectedSpace?.id ?? "")
case .askToJoinWithSpaceMembers:
return .askToJoinWithSpaceMembers(spaceID: selectedSpace?.id ?? "")
case .askToJoin:
return .askToJoin
case .private:
return .private
}
return availableTypes
}
}
struct CreateRoomScreenViewStateBindings {
var roomTopic: String
var selectedAccessType: CreateRoomAccessType
var selectedAccessType: CreateRoomScreenAccessType
var showAttachmentConfirmationDialog = false
/// Information describing the currently displayed alert.
@@ -102,3 +131,11 @@ extension Set<CreateRoomScreenAliasErrorState> {
return nil
}
}
enum CreateRoomScreenAccessType {
case `public`
case spaceMembers
case askToJoinWithSpaceMembers
case askToJoin
case `private`
}

View File

@@ -45,6 +45,7 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
roomName: "",
serverName: userSession.clientProxy.userIDServerName ?? "",
isKnockingFeatureEnabled: appSettings.knockingEnabled,
canSelectSpace: isSpace ? false : appSettings.createSpaceEnabled,
aliasLocalPart: roomAliasNameFromRoomDisplayName(roomName: ""),
bindings: bindings),
mediaProvider: userSession.mediaProvider)
@@ -114,9 +115,9 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
// Reset the state related to public rooms if the user choses the room to be empty
context.$viewState
.dropFirst()
.map(\.bindings.selectedAccessType)
.removeDuplicates()
.map(\.roomAccessType)
.filter(\.isPrivate)
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
guard let self else { return }
@@ -135,7 +136,7 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
return
}
guard !state.bindings.selectedAccessType.isPrivate,
guard !state.roomAccessType.isPrivate,
let canonicalAlias = String.makeCanonicalAlias(aliasLocalPart: aliasLocalPart,
serverName: state.serverName) else {
// While is empty or private room we don't change or display the error
@@ -167,6 +168,18 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
}
}
.store(in: &cancellables)
context.$viewState
.map(\.availableAccessTypes)
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [weak self] availableAccessTypes in
guard let self else { return }
if !availableAccessTypes.contains(state.bindings.selectedAccessType) {
state.bindings.selectedAccessType = .private
}
}
.store(in: &cancellables)
}
private func createRoom() async {
@@ -176,7 +189,7 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
showLoadingIndicator()
// Better to double check the errors also when trying to create the room
if !state.bindings.selectedAccessType.isPrivate {
if !state.roomAccessType.isPrivate {
guard let canonicalAlias = String.makeCanonicalAlias(aliasLocalPart: state.aliasLocalPart,
serverName: state.serverName),
isRoomAliasFormatValid(alias: canonicalAlias) else {
@@ -224,11 +237,11 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
switch await userSession.clientProxy.createRoom(name: state.roomName,
topic: state.bindings.roomTopic.isBlank ? nil : state.bindings.roomTopic,
accessType: state.bindings.selectedAccessType,
accessType: state.roomAccessType,
isSpace: state.isSpace,
userIDs: [], // The invite users screen is shown next so we don't need to invite anyone right now.
avatarURL: avatarURL,
aliasLocalPart: state.bindings.selectedAccessType.isPrivate ? nil : state.aliasLocalPart) {
aliasLocalPart: state.roomAccessType.isPrivate ? nil : state.aliasLocalPart) {
case .success(let roomID):
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
state.bindings.alertInfo = AlertInfo(id: .failedCreatingRoom,

View File

@@ -39,8 +39,11 @@ struct CreateRoomScreen: View {
Form {
roomSection
topicSection
if context.viewState.canSelectSpace {
selectSpaceSection
}
roomAccessSection
if !context.selectedAccessType.isPrivate {
if !context.viewState.roomAccessType.isPrivate {
roomAliasSection
}
}
@@ -181,6 +184,7 @@ struct CreateRoomScreen: View {
Section {
ForEach(context.viewState.availableAccessTypes, id: \.self) { accessType in
CreateRoomAccessRow(access: accessType,
spaceName: context.viewState.selectedSpace?.name ?? "",
isSelected: context.selectedAccessType == accessType) {
context.selectedAccessType = accessType
}
@@ -215,6 +219,15 @@ struct CreateRoomScreen: View {
}
}
private var selectSpaceSection: some View {
Section {
EmptyView()
} header: {
Text(L10n.commonSpace)
.compoundListSectionHeader()
}
}
@ToolbarContentBuilder
private var toolbar: some ToolbarContent {
if context.viewState.shouldShowCancelButton {
@@ -237,7 +250,8 @@ struct CreateRoomScreen: View {
}
private struct CreateRoomAccessRow: View {
let access: CreateRoomAccessType
let access: CreateRoomScreenAccessType
let spaceName: String
let isSelected: Bool
let onSelection: () -> Void
@@ -249,6 +263,10 @@ private struct CreateRoomAccessRow: View {
L10n.screenCreateRoomRoomAccessSectionKnockingOptionTitle
case .private:
L10n.screenCreateRoomRoomAccessSectionPrivateOptionTitle
case .spaceMembers:
L10n.screenCreateRoomRoomAccessSectionRestrictedOptionTitle
case .askToJoinWithSpaceMembers:
L10n.screenCreateRoomRoomAccessSectionKnockingRestrictedOptionTitle
}
}
@@ -260,6 +278,10 @@ private struct CreateRoomAccessRow: View {
L10n.screenCreateRoomRoomAccessSectionKnockingOptionDescription
case .private:
L10n.screenCreateRoomRoomAccessSectionPrivateOptionDescription
case .spaceMembers:
L10n.screenCreateRoomRoomAccessSectionRestrictedOptionDescription(spaceName)
case .askToJoinWithSpaceMembers:
L10n.screenCreateRoomRoomAccessSectionKnockingRestrictedOptionDescription(spaceName)
}
}
@@ -271,6 +293,10 @@ private struct CreateRoomAccessRow: View {
\.userAdd
case .private:
\.lock
case .spaceMembers:
\.space
case .askToJoinWithSpaceMembers:
\.userAdd
}
}

View File

@@ -513,7 +513,7 @@ class ClientProxy: ClientProxyProtocol {
Self.standardSpaceCreationPowerLevelOverrides
}
} else {
if accessType == .askToJoin {
if accessType.isAskToJoin {
Self.knockingRoomCreationPowerLevelOverrides
} else {
Self.roomCreationPowerLevelOverrides
@@ -1372,7 +1372,7 @@ private extension CreateRoomAccessType {
switch self {
case .public:
false
case .askToJoin, .private:
default:
true
}
}
@@ -1393,8 +1393,21 @@ private extension CreateRoomAccessType {
switch self {
case .askToJoin:
.knock
case .spaceMembers(let spaceID):
.restricted(rules: [.roomMembership(roomId: spaceID)])
case .askToJoinWithSpaceMembers(let spaceID):
.knockRestricted(rules: [.roomMembership(roomId: spaceID)])
case .private, .public:
nil
}
}
var isAskToJoin: Bool {
switch self {
case .askToJoin, .askToJoinWithSpaceMembers:
true
default:
false
}
}
}

View File

@@ -48,14 +48,16 @@ enum SlidingSyncConstants {
static let maximumVisibleRangeSize = 30
}
enum CreateRoomAccessType: CaseIterable {
enum CreateRoomAccessType: Equatable {
case `public`
case spaceMembers(spaceID: String)
case askToJoinWithSpaceMembers(spaceID: String)
case askToJoin
case `private`
var isPrivate: Bool {
switch self {
case .private:
case .private, .spaceMembers, .askToJoinWithSpaceMembers:
true
case .public, .askToJoin:
false