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:
Mauro
2024-10-14 11:52:38 +02:00
committed by GitHub
parent 25037a67ee
commit a16e1346fe
17 changed files with 149 additions and 37 deletions
@@ -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
+1 -1
View File
@@ -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")
} }
} }
@@ -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 { }
@@ -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?
} }
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2b6822fdd0ddc3b3c87d0142377a0951e9478c2fb1a1b840204589b2bc6270e
size 175831
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b805b55944beb58caccd5dbf4e98261582fe006ce8c08014bfaf26c13eea75f
size 211876
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0fccdc54a2d88e39353bdb49f32040749072dd17ac3c6cacc165ab6f0812d500
size 123697
@@ -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])
}
} }