mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 15:45:11 +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:
@@ -47,6 +47,7 @@ final class AppSettings {
|
|||||||
case pinningEnabled
|
case pinningEnabled
|
||||||
case enableOnlySignedDeviceIsolationMode
|
case enableOnlySignedDeviceIsolationMode
|
||||||
case identityPinningViolationNotificationsEnabled
|
case identityPinningViolationNotificationsEnabled
|
||||||
|
case knockingEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
||||||
@@ -282,6 +283,9 @@ final class AppSettings {
|
|||||||
|
|
||||||
@UserPreference(key: UserDefaultsKeys.identityPinningViolationNotificationsEnabled, defaultValue: isDevelopmentBuild, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.identityPinningViolationNotificationsEnabled, defaultValue: isDevelopmentBuild, storageType: .userDefaults(store))
|
||||||
var identityPinningViolationNotificationsEnabled
|
var identityPinningViolationNotificationsEnabled
|
||||||
|
|
||||||
|
@UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
|
var knockingEnabled
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ extension ClientProxyMock {
|
|||||||
canDeactivateAccount = false
|
canDeactivateAccount = false
|
||||||
directRoomForUserIDReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
directRoomForUserIDReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||||
createDirectRoomWithExpectedRoomNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
createDirectRoomWithExpectedRoomNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||||
uploadMediaReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
uploadMediaReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||||
loadUserDisplayNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
loadUserDisplayNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||||
setUserDisplayNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
setUserDisplayNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||||
|
|||||||
@@ -2627,15 +2627,15 @@ class ClientProxyMock: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
//MARK: - createRoom
|
//MARK: - createRoom
|
||||||
|
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingCallsCount = 0
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingCallsCount = 0
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLCallsCount: Int {
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLCallsCount: Int {
|
||||||
get {
|
get {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
return createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingCallsCount
|
return createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingCallsCount
|
||||||
} else {
|
} else {
|
||||||
var returnValue: Int? = nil
|
var returnValue: Int? = nil
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
returnValue = createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingCallsCount
|
returnValue = createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingCallsCount
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue!
|
return returnValue!
|
||||||
@@ -2643,29 +2643,29 @@ class ClientProxyMock: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingCallsCount = newValue
|
createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingCallsCount = newValue
|
||||||
} else {
|
} else {
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingCallsCount = newValue
|
createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingCallsCount = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLCalled: Bool {
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLCalled: Bool {
|
||||||
return createRoomNameTopicIsRoomPrivateUserIDsAvatarURLCallsCount > 0
|
return createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLCallsCount > 0
|
||||||
}
|
}
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReceivedArguments: (name: String, topic: String?, isRoomPrivate: Bool, userIDs: [String], avatarURL: URL?)?
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLReceivedArguments: (name: String, topic: String?, isRoomPrivate: Bool, isKnockingOnly: Bool, userIDs: [String], avatarURL: URL?)?
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReceivedInvocations: [(name: String, topic: String?, isRoomPrivate: Bool, userIDs: [String], avatarURL: URL?)] = []
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLReceivedInvocations: [(name: String, topic: String?, isRoomPrivate: Bool, isKnockingOnly: Bool, userIDs: [String], avatarURL: URL?)] = []
|
||||||
|
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingReturnValue: Result<String, ClientProxyError>!
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingReturnValue: Result<String, ClientProxyError>!
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReturnValue: Result<String, ClientProxyError>! {
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLReturnValue: Result<String, ClientProxyError>! {
|
||||||
get {
|
get {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
return createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingReturnValue
|
return createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingReturnValue
|
||||||
} else {
|
} else {
|
||||||
var returnValue: Result<String, ClientProxyError>? = nil
|
var returnValue: Result<String, ClientProxyError>? = nil
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
returnValue = createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingReturnValue
|
returnValue = createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingReturnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue!
|
return returnValue!
|
||||||
@@ -2673,26 +2673,26 @@ class ClientProxyMock: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingReturnValue = newValue
|
createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingReturnValue = newValue
|
||||||
} else {
|
} else {
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLUnderlyingReturnValue = newValue
|
createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLUnderlyingReturnValue = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var createRoomNameTopicIsRoomPrivateUserIDsAvatarURLClosure: ((String, String?, Bool, [String], URL?) async -> Result<String, ClientProxyError>)?
|
var createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure: ((String, String?, Bool, Bool, [String], URL?) async -> Result<String, ClientProxyError>)?
|
||||||
|
|
||||||
func createRoom(name: String, topic: String?, isRoomPrivate: Bool, userIDs: [String], avatarURL: URL?) async -> Result<String, ClientProxyError> {
|
func createRoom(name: String, topic: String?, isRoomPrivate: Bool, isKnockingOnly: Bool, userIDs: [String], avatarURL: URL?) async -> Result<String, ClientProxyError> {
|
||||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLCallsCount += 1
|
createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLCallsCount += 1
|
||||||
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReceivedArguments = (name: name, topic: topic, isRoomPrivate: isRoomPrivate, userIDs: userIDs, avatarURL: avatarURL)
|
createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLReceivedArguments = (name: name, topic: topic, isRoomPrivate: isRoomPrivate, isKnockingOnly: isKnockingOnly, userIDs: userIDs, avatarURL: avatarURL)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReceivedInvocations.append((name: name, topic: topic, isRoomPrivate: isRoomPrivate, userIDs: userIDs, avatarURL: avatarURL))
|
self.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLReceivedInvocations.append((name: name, topic: topic, isRoomPrivate: isRoomPrivate, isKnockingOnly: isKnockingOnly, userIDs: userIDs, avatarURL: avatarURL))
|
||||||
}
|
}
|
||||||
if let createRoomNameTopicIsRoomPrivateUserIDsAvatarURLClosure = createRoomNameTopicIsRoomPrivateUserIDsAvatarURLClosure {
|
if let createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure = createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure {
|
||||||
return await createRoomNameTopicIsRoomPrivateUserIDsAvatarURLClosure(name, topic, isRoomPrivate, userIDs, avatarURL)
|
return await createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure(name, topic, isRoomPrivate, isKnockingOnly, userIDs, avatarURL)
|
||||||
} else {
|
} else {
|
||||||
return createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReturnValue
|
return createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//MARK: - joinRoom
|
//MARK: - joinRoom
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ final class CreateRoomCoordinator: CoordinatorProtocol {
|
|||||||
createRoomParameters: parameters.createRoomParameters,
|
createRoomParameters: parameters.createRoomParameters,
|
||||||
selectedUsers: parameters.selectedUsers,
|
selectedUsers: parameters.selectedUsers,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
userIndicatorController: parameters.userIndicatorController)
|
userIndicatorController: parameters.userIndicatorController,
|
||||||
|
appSettings: ServiceLocator.shared.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func start() {
|
func start() {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ enum CreateRoomViewModelAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct CreateRoomViewState: BindableState {
|
struct CreateRoomViewState: BindableState {
|
||||||
|
let isKnockingFeatureEnabled: Bool
|
||||||
var selectedUsers: [UserProfileProxy]
|
var selectedUsers: [UserProfileProxy]
|
||||||
var bindings: CreateRoomViewStateBindings
|
var bindings: CreateRoomViewStateBindings
|
||||||
var avatarURL: URL?
|
var avatarURL: URL?
|
||||||
@@ -37,6 +38,7 @@ struct CreateRoomViewStateBindings {
|
|||||||
var roomName: String
|
var roomName: String
|
||||||
var roomTopic: String
|
var roomTopic: String
|
||||||
var isRoomPrivate: Bool
|
var isRoomPrivate: Bool
|
||||||
|
var isKnockingOnly = false
|
||||||
var showAttachmentConfirmationDialog = false
|
var showAttachmentConfirmationDialog = false
|
||||||
|
|
||||||
/// Information describing the currently displayed alert.
|
/// Information describing the currently displayed alert.
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
|||||||
createRoomParameters: CurrentValuePublisher<CreateRoomFlowParameters, Never>,
|
createRoomParameters: CurrentValuePublisher<CreateRoomFlowParameters, Never>,
|
||||||
selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>,
|
selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>,
|
||||||
analytics: AnalyticsService,
|
analytics: AnalyticsService,
|
||||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
userIndicatorController: UserIndicatorControllerProtocol,
|
||||||
|
appSettings: AppSettings) {
|
||||||
let parameters = createRoomParameters.value
|
let parameters = createRoomParameters.value
|
||||||
|
|
||||||
self.userSession = userSession
|
self.userSession = userSession
|
||||||
@@ -36,7 +37,7 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
|||||||
|
|
||||||
let bindings = CreateRoomViewStateBindings(roomName: parameters.name, roomTopic: parameters.topic, isRoomPrivate: parameters.isRoomPrivate)
|
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
|
createRoomParameters
|
||||||
.map(\.avatarImageMedia)
|
.map(\.avatarImageMedia)
|
||||||
@@ -92,21 +93,28 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
|||||||
old.roomName == new.roomName && old.roomTopic == new.roomTopic && old.isRoomPrivate == new.isRoomPrivate
|
old.roomName == new.roomName && old.roomTopic == new.roomTopic && old.isRoomPrivate == new.isRoomPrivate
|
||||||
}
|
}
|
||||||
.sink { [weak self] bindings in
|
.sink { [weak self] bindings in
|
||||||
guard let self else { return }
|
guard let self = self else { return }
|
||||||
createRoomParameters.name = bindings.roomName
|
updateParameters(bindings: bindings)
|
||||||
createRoomParameters.topic = bindings.roomTopic
|
|
||||||
createRoomParameters.isRoomPrivate = bindings.isRoomPrivate
|
|
||||||
actionsSubject.send(.updateDetails(createRoomParameters))
|
actionsSubject.send(.updateDetails(createRoomParameters))
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.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 {
|
private func createRoom() async {
|
||||||
defer {
|
defer {
|
||||||
hideLoadingIndicator()
|
hideLoadingIndicator()
|
||||||
}
|
}
|
||||||
showLoadingIndicator()
|
showLoadingIndicator()
|
||||||
|
|
||||||
|
// Since the parameters are throttled, we need to make sure that the latest values are used
|
||||||
|
updateParameters(bindings: state.bindings)
|
||||||
let avatarURL: URL?
|
let avatarURL: URL?
|
||||||
if let media = createRoomParameters.avatarImageMedia {
|
if let media = createRoomParameters.avatarImageMedia {
|
||||||
switch await userSession.clientProxy.uploadMedia(media) {
|
switch await userSession.clientProxy.uploadMedia(media) {
|
||||||
@@ -136,6 +144,8 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
|
|||||||
switch await userSession.clientProxy.createRoom(name: createRoomParameters.name,
|
switch await userSession.clientProxy.createRoom(name: createRoomParameters.name,
|
||||||
topic: createRoomParameters.topic,
|
topic: createRoomParameters.topic,
|
||||||
isRoomPrivate: createRoomParameters.isRoomPrivate,
|
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),
|
userIDs: state.selectedUsers.map(\.userID),
|
||||||
avatarURL: avatarURL) {
|
avatarURL: avatarURL) {
|
||||||
case .success(let roomId):
|
case .success(let roomId):
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ struct CreateRoomScreen: View {
|
|||||||
roomSection
|
roomSection
|
||||||
topicSection
|
topicSection
|
||||||
securitySection
|
securitySection
|
||||||
|
if context.viewState.isKnockingFeatureEnabled,
|
||||||
|
!context.isRoomPrivate {
|
||||||
|
roomAccessSection
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.compoundList()
|
.compoundList()
|
||||||
.track(screen: .CreateRoom)
|
.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 {
|
private var toolbar: some ToolbarContent {
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
Button(L10n.actionCreate) {
|
Button(L10n.actionCreate) {
|
||||||
@@ -174,7 +192,8 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
|||||||
createRoomParameters: .init(parameters),
|
createRoomParameters: .init(parameters),
|
||||||
selectedUsers: .init(selectedUsers),
|
selectedUsers: .init(selectedUsers),
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
|
appSettings: ServiceLocator.shared.settings)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
static let emtpyViewModel = {
|
static let emtpyViewModel = {
|
||||||
@@ -184,7 +203,21 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
|||||||
createRoomParameters: .init(parameters),
|
createRoomParameters: .init(parameters),
|
||||||
selectedUsers: .init([]),
|
selectedUsers: .init([]),
|
||||||
analytics: ServiceLocator.shared.analytics,
|
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 {
|
static var previews: some View {
|
||||||
@@ -196,5 +229,9 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
|||||||
CreateRoomScreen(context: emtpyViewModel.context)
|
CreateRoomScreen(context: emtpyViewModel.context)
|
||||||
}
|
}
|
||||||
.previewDisplayName("Create Room without users")
|
.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 enableOnlySignedDeviceIsolationMode: Bool { get set }
|
||||||
var elementCallBaseURLOverride: URL? { get set }
|
var elementCallBaseURLOverride: URL? { get set }
|
||||||
var identityPinningViolationNotificationsEnabled: Bool { get set }
|
var identityPinningViolationNotificationsEnabled: Bool { get set }
|
||||||
|
var knockingEnabled: Bool { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppSettings: DeveloperOptionsProtocol { }
|
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 {
|
Section {
|
||||||
Toggle(isOn: $context.enableOnlySignedDeviceIsolationMode) {
|
Toggle(isOn: $context.enableOnlySignedDeviceIsolationMode) {
|
||||||
Text("Exclude insecure devices when sending/receiving messages")
|
Text("Exclude insecure devices when sending/receiving messages")
|
||||||
|
|||||||
@@ -365,8 +365,9 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRoom(name: String, topic: String?, isRoomPrivate: Bool, userIDs: [String], avatarURL: URL?) async -> Result<String, ClientProxyError> {
|
func createRoom(name: String, topic: String?, isRoomPrivate: Bool, isKnockingOnly: Bool, userIDs: [String], avatarURL: URL?) async -> Result<String, ClientProxyError> {
|
||||||
do {
|
do {
|
||||||
|
// TODO: Revisit once the SDK supports the knocking API
|
||||||
let parameters = CreateRoomParameters(name: name,
|
let parameters = CreateRoomParameters(name: name,
|
||||||
topic: topic,
|
topic: topic,
|
||||||
isEncrypted: isRoomPrivate,
|
isEncrypted: isRoomPrivate,
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
|||||||
|
|
||||||
func createDirectRoom(with userID: String, expectedRoomName: String?) async -> Result<String, ClientProxyError>
|
func createDirectRoom(with userID: String, expectedRoomName: String?) async -> Result<String, ClientProxyError>
|
||||||
|
|
||||||
func createRoom(name: String, topic: String?, isRoomPrivate: Bool, userIDs: [String], avatarURL: URL?) async -> Result<String, ClientProxyError>
|
func createRoom(name: String, topic: String?, isRoomPrivate: Bool, isKnockingOnly: Bool, userIDs: [String], avatarURL: URL?) async -> Result<String, ClientProxyError>
|
||||||
|
|
||||||
func joinRoom(_ roomID: String, via: [String]) async -> Result<Void, ClientProxyError>
|
func joinRoom(_ roomID: String, via: [String]) async -> Result<Void, ClientProxyError>
|
||||||
|
|
||||||
|
|||||||
@@ -12,5 +12,6 @@ struct CreateRoomFlowParameters {
|
|||||||
var name = ""
|
var name = ""
|
||||||
var topic = ""
|
var topic = ""
|
||||||
var isRoomPrivate = true
|
var isRoomPrivate = true
|
||||||
|
var isKnockingOnly = false
|
||||||
var avatarImageMedia: MediaInfo?
|
var avatarImageMedia: MediaInfo?
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:a2b6822fdd0ddc3b3c87d0142377a0951e9478c2fb1a1b840204589b2bc6270e
|
||||||
|
size 175831
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:1b805b55944beb58caccd5dbf4e98261582fe006ce8c08014bfaf26c13eea75f
|
||||||
|
size 211876
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:0fccdc54a2d88e39353bdb49f32040749072dd17ac3c6cacc165ab6f0812d500
|
||||||
|
size 123697
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:35ecf1e814eedd5f2d388224aee6fc885b1d9e1fe174b9199d9fe7bb9004a355
|
||||||
|
size 164558
|
||||||
@@ -29,11 +29,13 @@ class CreateRoomScreenViewModelTests: XCTestCase {
|
|||||||
userSession = UserSessionMock(.init(clientProxy: clientProxy))
|
userSession = UserSessionMock(.init(clientProxy: clientProxy))
|
||||||
let parameters = CreateRoomFlowParameters()
|
let parameters = CreateRoomFlowParameters()
|
||||||
usersSubject.send([.mockAlice, .mockBob, .mockCharlie])
|
usersSubject.send([.mockAlice, .mockBob, .mockCharlie])
|
||||||
|
ServiceLocator.shared.settings.knockingEnabled = true
|
||||||
let viewModel = CreateRoomViewModel(userSession: userSession,
|
let viewModel = CreateRoomViewModel(userSession: userSession,
|
||||||
createRoomParameters: .init(parameters),
|
createRoomParameters: .init(parameters),
|
||||||
selectedUsers: usersSubject.asCurrentValuePublisher(),
|
selectedUsers: usersSubject.asCurrentValuePublisher(),
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
|
appSettings: ServiceLocator.shared.settings)
|
||||||
self.viewModel = viewModel
|
self.viewModel = viewModel
|
||||||
|
|
||||||
viewModel.actions.sink { [weak self] action in
|
viewModel.actions.sink { [weak self] action in
|
||||||
@@ -69,4 +71,38 @@ class CreateRoomScreenViewModelTests: XCTestCase {
|
|||||||
context.roomName = "A"
|
context.roomName = "A"
|
||||||
XCTAssertTrue(context.viewState.canCreateRoom)
|
XCTAssertTrue(context.viewState.canCreateRoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCreateKnockingRoom() async {
|
||||||
|
context.roomName = "A"
|
||||||
|
context.roomTopic = "B"
|
||||||
|
context.isRoomPrivate = false
|
||||||
|
context.isKnockingOnly = true
|
||||||
|
XCTAssertTrue(context.viewState.canCreateRoom)
|
||||||
|
|
||||||
|
let expectation = expectation(description: "Wait for the room to be created")
|
||||||
|
clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure = { _, _, isPrivate, isKnockingOnly, _, _ in
|
||||||
|
XCTAssertTrue(isKnockingOnly)
|
||||||
|
XCTAssertFalse(isPrivate)
|
||||||
|
defer { expectation.fulfill() }
|
||||||
|
return .success("")
|
||||||
|
}
|
||||||
|
context.send(viewAction: .createRoom)
|
||||||
|
await fulfillment(of: [expectation])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCreatePrivateRoomCantHaveKnockRule() async {
|
||||||
|
context.roomName = "A"
|
||||||
|
context.roomTopic = "B"
|
||||||
|
context.isRoomPrivate = true
|
||||||
|
context.isKnockingOnly = true
|
||||||
|
context.send(viewAction: .createRoom)
|
||||||
|
let expectation = expectation(description: "Wait for the room to be created")
|
||||||
|
clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure = { _, _, isPrivate, isKnockingOnly, _, _ in
|
||||||
|
XCTAssertFalse(isKnockingOnly)
|
||||||
|
XCTAssertTrue(isPrivate)
|
||||||
|
expectation.fulfill()
|
||||||
|
return .success("")
|
||||||
|
}
|
||||||
|
await fulfillment(of: [expectation])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user