mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Create Room with knock rule (#3397)
* create knock room implementation (without SDK) * Apply suggestions from code review pr suggestions Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * pr suggestions --------- Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com>
This commit is contained in:
@@ -37,7 +37,8 @@ final class CreateRoomCoordinator: CoordinatorProtocol {
|
||||
createRoomParameters: parameters.createRoomParameters,
|
||||
selectedUsers: parameters.selectedUsers,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}
|
||||
|
||||
func start() {
|
||||
|
||||
@@ -25,6 +25,7 @@ enum CreateRoomViewModelAction {
|
||||
}
|
||||
|
||||
struct CreateRoomViewState: BindableState {
|
||||
let isKnockingFeatureEnabled: Bool
|
||||
var selectedUsers: [UserProfileProxy]
|
||||
var bindings: CreateRoomViewStateBindings
|
||||
var avatarURL: URL?
|
||||
@@ -37,6 +38,7 @@ struct CreateRoomViewStateBindings {
|
||||
var roomName: String
|
||||
var roomTopic: String
|
||||
var isRoomPrivate: Bool
|
||||
var isKnockingOnly = false
|
||||
var showAttachmentConfirmationDialog = false
|
||||
|
||||
/// Information describing the currently displayed alert.
|
||||
|
||||
@@ -26,7 +26,8 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
||||
createRoomParameters: CurrentValuePublisher<CreateRoomFlowParameters, Never>,
|
||||
selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>,
|
||||
analytics: AnalyticsService,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
appSettings: AppSettings) {
|
||||
let parameters = createRoomParameters.value
|
||||
|
||||
self.userSession = userSession
|
||||
@@ -36,7 +37,7 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
||||
|
||||
let bindings = CreateRoomViewStateBindings(roomName: parameters.name, roomTopic: parameters.topic, isRoomPrivate: parameters.isRoomPrivate)
|
||||
|
||||
super.init(initialViewState: CreateRoomViewState(selectedUsers: selectedUsers.value, bindings: bindings), mediaProvider: userSession.mediaProvider)
|
||||
super.init(initialViewState: CreateRoomViewState(isKnockingFeatureEnabled: appSettings.knockingEnabled, selectedUsers: selectedUsers.value, bindings: bindings), mediaProvider: userSession.mediaProvider)
|
||||
|
||||
createRoomParameters
|
||||
.map(\.avatarImageMedia)
|
||||
@@ -92,21 +93,28 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
||||
old.roomName == new.roomName && old.roomTopic == new.roomTopic && old.isRoomPrivate == new.isRoomPrivate
|
||||
}
|
||||
.sink { [weak self] bindings in
|
||||
guard let self else { return }
|
||||
createRoomParameters.name = bindings.roomName
|
||||
createRoomParameters.topic = bindings.roomTopic
|
||||
createRoomParameters.isRoomPrivate = bindings.isRoomPrivate
|
||||
guard let self = self else { return }
|
||||
updateParameters(bindings: bindings)
|
||||
actionsSubject.send(.updateDetails(createRoomParameters))
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func updateParameters(bindings: CreateRoomViewStateBindings) {
|
||||
createRoomParameters.name = bindings.roomName
|
||||
createRoomParameters.topic = bindings.roomTopic
|
||||
createRoomParameters.isRoomPrivate = bindings.isRoomPrivate
|
||||
createRoomParameters.isKnockingOnly = bindings.isKnockingOnly
|
||||
}
|
||||
|
||||
private func createRoom() async {
|
||||
defer {
|
||||
hideLoadingIndicator()
|
||||
}
|
||||
showLoadingIndicator()
|
||||
|
||||
// Since the parameters are throttled, we need to make sure that the latest values are used
|
||||
updateParameters(bindings: state.bindings)
|
||||
let avatarURL: URL?
|
||||
if let media = createRoomParameters.avatarImageMedia {
|
||||
switch await userSession.clientProxy.uploadMedia(media) {
|
||||
@@ -136,6 +144,8 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
||||
switch await userSession.clientProxy.createRoom(name: createRoomParameters.name,
|
||||
topic: createRoomParameters.topic,
|
||||
isRoomPrivate: createRoomParameters.isRoomPrivate,
|
||||
// As of right now we don't want to make private rooms with the knock rule
|
||||
isKnockingOnly: createRoomParameters.isRoomPrivate ? false : createRoomParameters.isKnockingOnly,
|
||||
userIDs: state.selectedUsers.map(\.userID),
|
||||
avatarURL: avatarURL) {
|
||||
case .success(let roomId):
|
||||
|
||||
@@ -22,6 +22,10 @@ struct CreateRoomScreen: View {
|
||||
roomSection
|
||||
topicSection
|
||||
securitySection
|
||||
if context.viewState.isKnockingFeatureEnabled,
|
||||
!context.isRoomPrivate {
|
||||
roomAccessSection
|
||||
}
|
||||
}
|
||||
.compoundList()
|
||||
.track(screen: .CreateRoom)
|
||||
@@ -151,6 +155,20 @@ struct CreateRoomScreen: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var roomAccessSection: some View {
|
||||
Section {
|
||||
ListRow(label: .plain(title: L10n.screenCreateRoomAccessSectionAnyoneOptionTitle,
|
||||
description: L10n.screenCreateRoomAccessSectionAnyoneOptionDescription),
|
||||
kind: .selection(isSelected: !context.isKnockingOnly) { context.isKnockingOnly = false })
|
||||
ListRow(label: .plain(title: L10n.screenCreateRoomAccessSectionKnockingOptionTitle,
|
||||
description: L10n.screenCreateRoomAccessSectionKnockingOptionDescription),
|
||||
kind: .selection(isSelected: context.isKnockingOnly) { context.isKnockingOnly = true })
|
||||
} header: {
|
||||
Text(L10n.screenCreateRoomAccessSectionHeader.uppercased())
|
||||
.compoundListSectionHeader()
|
||||
}
|
||||
}
|
||||
|
||||
private var toolbar: some ToolbarContent {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button(L10n.actionCreate) {
|
||||
@@ -174,7 +192,8 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
||||
createRoomParameters: .init(parameters),
|
||||
selectedUsers: .init(selectedUsers),
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock())
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}()
|
||||
|
||||
static let emtpyViewModel = {
|
||||
@@ -184,7 +203,21 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
||||
createRoomParameters: .init(parameters),
|
||||
selectedUsers: .init([]),
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock())
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}()
|
||||
|
||||
static let publicRoomViewModel = {
|
||||
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
|
||||
let parameters = CreateRoomFlowParameters(isRoomPrivate: false)
|
||||
let selectedUsers: [UserProfileProxy] = [.mockAlice, .mockBob, .mockCharlie]
|
||||
ServiceLocator.shared.settings.knockingEnabled = true
|
||||
return CreateRoomViewModel(userSession: userSession,
|
||||
createRoomParameters: .init(parameters),
|
||||
selectedUsers: .init([]),
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
@@ -196,5 +229,9 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
||||
CreateRoomScreen(context: emtpyViewModel.context)
|
||||
}
|
||||
.previewDisplayName("Create Room without users")
|
||||
NavigationStack {
|
||||
CreateRoomScreen(context: publicRoomViewModel.context)
|
||||
}
|
||||
.previewDisplayName("Create Public Room")
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
||||
var enableOnlySignedDeviceIsolationMode: Bool { get set }
|
||||
var elementCallBaseURLOverride: URL? { get set }
|
||||
var identityPinningViolationNotificationsEnabled: Bool { get set }
|
||||
var knockingEnabled: Bool { get set }
|
||||
}
|
||||
|
||||
extension AppSettings: DeveloperOptionsProtocol { }
|
||||
|
||||
+7
@@ -55,6 +55,13 @@ struct DeveloperOptionsScreen: View {
|
||||
}
|
||||
}
|
||||
|
||||
Section("Join rules") {
|
||||
Toggle(isOn: $context.knockingEnabled) {
|
||||
Text("Knocking")
|
||||
Text("Experimental, still using mocked data")
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Toggle(isOn: $context.enableOnlySignedDeviceIsolationMode) {
|
||||
Text("Exclude insecure devices when sending/receiving messages")
|
||||
|
||||
Reference in New Issue
Block a user