Files
letro-ios/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift
Doug b3d4ed0274 Introduce a StartChatFlowCoordinator instead of handing a navigation stack to the Screen Coordinator. (#4674)
* Introduce a basic StartChatFlowCoordinator.

* Move the rest of the start chat flow from the screen coordinator into the flow coordinator.

* Add a UI test for the entire start chat flow.

* Refactor CreateRoom… to CreateRoomScreen…
2025-10-30 16:12:56 +00:00

206 lines
8.4 KiB
Swift

//
// Copyright 2025 Element Creations Ltd.
// Copyright 2023-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Combine
import Foundation
import MatrixRustSDK
enum RoomProxyMockError: Error {
case generic
}
@MainActor
struct JoinedRoomProxyMockConfiguration {
var id = UUID().uuidString
var name: String?
var topic: String?
var avatarURL: URL?
var isDirect = false
var isSpace = false
var isEncrypted = true
var hasOngoingCall = true
var canonicalAlias: String?
var alternativeAliases: [String] = []
var pinnedEventIDs: Set<String> = []
var timelineStartReached = false
var members: [RoomMemberProxyMock] = .allMembers
var heroes: [RoomMemberProxyMock] = []
var knockRequestsState: KnockRequestsState = .loaded([])
var ownUserID = RoomMemberProxyMock.mockMe.userID
var inviter: RoomMemberProxyProtocol?
var shouldUseAutoUpdatingTimeline = false
var joinRule: JoinRule? = .invite
var membership: Membership = .joined
var isVisibleInPublicDirectory = false
var predecessor: PredecessorRoom?
var successor: SuccessorRoom?
var powerLevelsConfiguration = RoomPowerLevelsProxyMockConfiguration()
}
extension JoinedRoomProxyMock {
@MainActor
convenience init(_ configuration: JoinedRoomProxyMockConfiguration) {
self.init()
id = configuration.id
timeline = TimelineProxyMock(.init(isAutoUpdating: configuration.shouldUseAutoUpdatingTimeline,
timelineStartReached: configuration.timelineStartReached))
pinnedEventsTimelineReturnValue = .failure(.failedCreatingPinnedTimeline)
ownUserID = configuration.ownUserID
membersPublisher = CurrentValueSubject(configuration.members).asCurrentValuePublisher()
knockRequestsStatePublisher = CurrentValueSubject(configuration.knockRequestsState).asCurrentValuePublisher()
typingMembersPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
identityStatusChangesPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
updateMembersClosure = { }
setNameClosure = { _ in .success(()) }
setTopicClosure = { _ in .success(()) }
getMemberUserIDClosure = { [weak self] userID in
guard let member = self?.membersPublisher.value.first(where: { $0.userID == userID }) else {
return .failure(.sdkError(RoomProxyMockError.generic))
}
return .success(member)
}
ignoreDeviceTrustAndResendDevicesSendHandleReturnValue = .success(())
withdrawVerificationAndResendUserIDsSendHandleReturnValue = .success(())
flagAsUnreadReturnValue = .success(())
markAsReadReceiptTypeReturnValue = .success(())
flagAsFavouriteReturnValue = .success(())
applyPowerLevelChangesReturnValue = .success(())
resetPowerLevelsReturnValue = .success(())
suggestedRoleForClosure = { [weak self] userID in
guard case .success(let member) = await self?.getMember(userID: userID) else {
return .failure(.sdkError(RoomProxyMockError.generic))
}
return .success(member.role.rustRole)
}
updatePowerLevelsForUsersReturnValue = .success(())
let powerLevelsProxyMock = RoomPowerLevelsProxyMock(configuration: configuration.powerLevelsConfiguration)
powerLevelsProxyMock.canUserUserIDSendStateEventClosure = { [weak self] userID, _ in
.success(self?.membersPublisher.value.first { $0.userID == userID }?.role ?? .user != .user)
}
powerLevelsProxyMock.canOwnUserSendStateEventClosure = { [weak self] _ in
self?.membersPublisher.value.first { $0.userID == configuration.ownUserID }?.role ?? .user != .user
}
powerLevelsProxyMock.canUserKickUserIDClosure = { [weak self] userID in
.success(self?.membersPublisher.value.first { $0.userID == userID }?.role ?? .user != .user)
}
powerLevelsProxyMock.canOwnUserKickClosure = { [weak self] in
self?.membersPublisher.value.first { $0.userID == configuration.ownUserID }?.role ?? .user != .user
}
powerLevelsProxyMock.canUserBanUserIDClosure = { [weak self] userID in
.success(self?.membersPublisher.value.first { $0.userID == userID }?.role ?? .user != .user)
}
powerLevelsProxyMock.canOwnUserBanClosure = { [weak self] in
self?.membersPublisher.value.first { $0.userID == configuration.ownUserID }?.role ?? .user != .user
}
powerLevelsProxyMock.canOwnUserEditRolesAndPermissionsClosure = { [weak self] in
self?.membersPublisher.value.first { $0.userID == configuration.ownUserID }?.role.isAdminOrHigher ?? false
}
powerLevelsReturnValue = .success(powerLevelsProxyMock)
inviteUserIDReturnValue = .success(())
kickUserReasonReturnValue = .success(())
banUserReasonReturnValue = .success(())
unbanUserReturnValue = .success(())
let widgetDriver = ElementCallWidgetDriverMock()
widgetDriver.underlyingMessagePublisher = .init()
widgetDriver.underlyingActions = PassthroughSubject().eraseToAnyPublisher()
guard let url = URL(string: "https://call.element.io/\(UUID().uuidString)#?appPrompt=false") else {
fatalError()
}
widgetDriver.startBaseURLClientIDColorSchemeRageshakeURLAnalyticsConfigurationReturnValue = .success(url)
elementCallWidgetDriverDeviceIDReturnValue = widgetDriver
matrixToPermalinkReturnValue = .success(.homeDirectory)
matrixToEventPermalinkReturnValue = .success(.homeDirectory)
loadDraftThreadRootEventIDReturnValue = .success(nil)
clearDraftThreadRootEventIDReturnValue = .success(())
sendTypingNotificationIsTypingReturnValue = .success(())
isVisibleInRoomDirectoryReturnValue = .success(configuration.isVisibleInPublicDirectory)
predecessorRoom = configuration.predecessor
let roomInfoProxyMock = RoomInfoProxyMock(configuration)
roomInfoProxyMock.powerLevels = powerLevelsProxyMock
infoPublisher = CurrentValueSubject(roomInfoProxyMock).asCurrentValuePublisher()
}
}
extension RoomInfoProxyMock {
@MainActor convenience init(_ configuration: JoinedRoomProxyMockConfiguration) {
self.init()
id = configuration.id
isEncrypted = configuration.isEncrypted
creators = []
displayName = configuration.name
rawName = configuration.name
topic = configuration.topic
avatarURL = configuration.avatarURL
isDirect = configuration.isDirect
isSpace = configuration.isSpace
successor = configuration.successor
isFavourite = false
canonicalAlias = configuration.canonicalAlias
alternativeAliases = configuration.alternativeAliases
membership = configuration.membership
inviter = configuration.inviter
heroes = configuration.heroes.map(RoomHero.init)
activeMembersCount = configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count
invitedMembersCount = configuration.members.filter { $0.membership == .invite }.count
joinedMembersCount = configuration.members.filter { $0.membership == .join }.count
highlightCount = 0
notificationCount = 0
cachedUserDefinedNotificationMode = .allMessages
hasRoomCall = configuration.hasOngoingCall
activeRoomCallParticipants = []
isMarkedUnread = false
unreadMessagesCount = 0
unreadNotificationsCount = 0
unreadMentionsCount = 0
pinnedEventIDs = configuration.pinnedEventIDs
joinRule = configuration.joinRule
historyVisibility = .shared
powerLevels = RoomPowerLevelsProxyMock(configuration: configuration.powerLevelsConfiguration)
}
}
private extension RoomHero {
init(from memberProxy: RoomMemberProxyMock) {
self.init(userId: memberProxy.userID,
displayName: memberProxy.displayName,
avatarUrl: memberProxy.avatarURL?.absoluteString)
}
}