Introduce a new RoomProxyType and treat rooms differently based on their membership state

This commit is contained in:
Stefan Ceriu
2024-08-20 16:13:27 +03:00
committed by Stefan Ceriu
parent e0ba9925e7
commit e281a3f242
97 changed files with 3755 additions and 3474 deletions
@@ -325,10 +325,15 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
guard let roomID = content.userInfo[NotificationConstants.UserInfoKey.roomIdentifier] as? String else {
return
}
let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID)
switch await roomProxy?.timeline.sendMessage(replyText,
html: nil,
intentionalMentions: .empty) {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
MXLog.error("Tried to reply in an unjoined room: \(roomID)")
return
}
switch await roomProxy.timeline.sendMessage(replyText,
html: nil,
intentionalMentions: .empty) {
case .success:
break
default:
@@ -20,7 +20,7 @@ import SwiftUI
import UserNotifications
enum RoomFlowCoordinatorAction: Equatable {
case presentCallScreen(roomProxy: RoomProxyProtocol)
case presentCallScreen(roomProxy: JoinedRoomProxyProtocol)
case finished
static func == (lhs: RoomFlowCoordinatorAction, rhs: RoomFlowCoordinatorAction) -> Bool {
@@ -63,7 +63,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
private let analytics: AnalyticsService
private let userIndicatorController: UserIndicatorControllerProtocol
private var roomProxy: RoomProxyProtocol!
private var roomProxy: JoinedRoomProxyProtocol!
private var roomScreenCoordinator: RoomScreenCoordinator?
private weak var joinRoomScreenCoordinator: JoinRoomScreenCoordinator?
@@ -139,7 +139,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
Task {
if roomProxy == nil {
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
return
}
@@ -173,7 +173,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
private func presentCallScreen(roomID: String) async {
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
return
}
@@ -183,13 +183,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
private func handleRoomRoute(roomID: String, via: [String], focussedEventID: String? = nil, animated: Bool) async {
guard roomID == self.roomID else { fatalError("Navigation route doesn't belong to this room flow.") }
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
guard let room = await userSession.clientProxy.roomForIdentifier(roomID) else {
stateMachine.tryEvent(.presentJoinRoomScreen(via: via), userInfo: EventUserInfo(animated: animated))
return
}
switch roomProxy.membership {
case .joined:
switch room {
case .joined(let roomProxy):
await storeAndSubscribeToRoomProxy(roomProxy)
stateMachine.tryEvent(.presentRoom(focussedEventID: focussedEventID), userInfo: EventUserInfo(animated: animated))
default:
@@ -207,7 +207,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
// MARK: - Private
private func storeAndSubscribeToRoomProxy(_ roomProxy: RoomProxyProtocol) async {
private func storeAndSubscribeToRoomProxy(_ roomProxy: JoinedRoomProxyProtocol) async {
if let oldRoomProxy = self.roomProxy {
if oldRoomProxy.id != roomProxy.id {
fatalError("Trying to create different room proxies for the same flow coordinator")
@@ -216,11 +216,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
MXLog.warning("Found an existing proxy, returning.")
return
}
guard roomProxy.membership == .joined else {
fatalError("Requesting room details for an unjoined room")
}
await roomProxy.subscribeForUpdates()
// Make sure not to set this until after the subscription has succeeded, otherwise the
@@ -658,7 +654,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
Task { [weak self] in
guard let self else { return }
if let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) {
if case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) {
await storeAndSubscribeToRoomProxy(roomProxy)
stateMachine.tryEvent(.presentRoom(focussedEventID: nil), userInfo: EventUserInfo(animated: animated))
@@ -1300,7 +1296,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
}
private func inviteUsers(_ users: [String], in room: RoomProxyProtocol) {
private func inviteUsers(_ users: [String], in room: JoinedRoomProxyProtocol) {
navigationStackCoordinator.setSheetCoordinator(nil)
Task {
@@ -24,7 +24,7 @@ enum RoomRolesAndPermissionsFlowCoordinatorAction: Equatable {
}
struct RoomRolesAndPermissionsFlowCoordinatorParameters {
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let mediaProvider: MediaProviderProtocol
let navigationStackCoordinator: NavigationStackCoordinator
let userIndicatorController: UserIndicatorControllerProtocol
@@ -32,7 +32,7 @@ struct RoomRolesAndPermissionsFlowCoordinatorParameters {
}
class RoomRolesAndPermissionsFlowCoordinator: FlowCoordinatorProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let navigationStackCoordinator: NavigationStackCoordinator
private let mediaProvider: MediaProviderProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
@@ -561,14 +561,14 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
}
private func presentCallScreen(roomID: String) async {
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
return
}
presentCallScreen(roomProxy: roomProxy)
}
private func presentCallScreen(roomProxy: RoomProxyProtocol) {
private func presentCallScreen(roomProxy: JoinedRoomProxyProtocol) {
let colorScheme: ColorScheme = appMediator.windowManager.mainWindow.traitCollection.userInterfaceStyle == .light ? .light : .dark
presentCallScreen(configuration: .init(roomProxy: roomProxy,
clientProxy: userSession.clientProxy,
+1 -1
View File
@@ -94,7 +94,7 @@ extension ClientProxyMock {
return nil
}
return await RoomProxyMock(.init(id: room.id, name: room.name))
return await .joined(JoinedRoomProxyMock(.init(id: room.id, name: room.name)))
}
}
}
File diff suppressed because it is too large Load Diff
@@ -9863,6 +9863,82 @@ open class NotificationSettingsSDKMock: MatrixRustSDK.NotificationSettings {
try await unmuteRoomRoomIdIsEncryptedIsOneToOneClosure?(roomId, isEncrypted, isOneToOne)
}
}
open class OidcAuthorizationDataSDKMock: MatrixRustSDK.OidcAuthorizationData {
init() {
super.init(noPointer: .init())
}
public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
fatalError("init(unsafeFromRawPointer:) has not been implemented")
}
fileprivate var pointer: UnsafeMutableRawPointer!
//MARK: - loginUrl
var loginUrlUnderlyingCallsCount = 0
open var loginUrlCallsCount: Int {
get {
if Thread.isMainThread {
return loginUrlUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = loginUrlUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
loginUrlUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
loginUrlUnderlyingCallsCount = newValue
}
}
}
}
open var loginUrlCalled: Bool {
return loginUrlCallsCount > 0
}
var loginUrlUnderlyingReturnValue: String!
open var loginUrlReturnValue: String! {
get {
if Thread.isMainThread {
return loginUrlUnderlyingReturnValue
} else {
var returnValue: String? = nil
DispatchQueue.main.sync {
returnValue = loginUrlUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
loginUrlUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
loginUrlUnderlyingReturnValue = newValue
}
}
}
}
open var loginUrlClosure: (() -> String)?
open override func loginUrl() -> String {
loginUrlCallsCount += 1
if let loginUrlClosure = loginUrlClosure {
return loginUrlClosure()
} else {
return loginUrlReturnValue
}
}
}
open class QrCodeDataSDKMock: MatrixRustSDK.QrCodeData {
init() {
super.init(noPointer: .init())
@@ -17,8 +17,12 @@
import Combine
import Foundation
enum RoomProxyMockError: Error {
case generic
}
@MainActor
struct RoomProxyMockConfiguration {
struct JoinedRoomProxyMockConfiguration {
var id = UUID().uuidString
var name: String?
var topic: String?
@@ -45,13 +49,9 @@ struct RoomProxyMockConfiguration {
var shouldUseAutoUpdatingTimeline = false
}
enum RoomProxyMockError: Error {
case generic
}
extension RoomProxyMock {
extension JoinedRoomProxyMock {
@MainActor
convenience init(_ configuration: RoomProxyMockConfiguration) {
convenience init(_ configuration: JoinedRoomProxyMockConfiguration) {
self.init()
id = configuration.id
@@ -86,8 +86,6 @@ extension RoomProxyMock {
self.timeline = timeline
ownUserID = configuration.ownUserID
membership = .joined
inviterClosure = { configuration.inviter }
membersPublisher = CurrentValueSubject(configuration.members).asCurrentValuePublisher()
typingMembersPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
@@ -96,7 +94,6 @@ extension RoomProxyMock {
activeMembersCount = configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count
updateMembersClosure = { }
acceptInvitationClosure = { .success(()) }
underlyingActionsPublisher = Empty(completeImmediately: false).eraseToAnyPublisher()
setNameClosure = { _ in .success(()) }
setTopicClosure = { _ in .success(()) }
@@ -208,7 +208,7 @@ struct CallScreen_Previews: PreviewProvider {
clientProxy.getElementWellKnownReturnValue = .success(nil)
clientProxy.deviceID = "call-device-id"
let roomProxy = RoomProxyMock()
let roomProxy = JoinedRoomProxyMock()
roomProxy.sendCallNotificationIfNeededReturnValue = .success(())
let widgetDriver = ElementCallWidgetDriverMock()
@@ -142,9 +142,9 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
case .showRoomDetails(roomIdentifier: let roomIdentifier):
actionsSubject.send(.presentRoomDetails(roomIdentifier: roomIdentifier))
case .leaveRoom(roomIdentifier: let roomIdentifier):
startLeaveRoomProcess(roomId: roomIdentifier)
startLeaveRoomProcess(roomID: roomIdentifier)
case .confirmLeaveRoom(roomIdentifier: let roomIdentifier):
leaveRoom(roomId: roomIdentifier)
Task { await leaveRoom(roomID: roomIdentifier) }
case .showSettings:
actionsSubject.send(.presentSettingsScreen)
case .confirmRecoveryKey:
@@ -159,7 +159,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
actionsSubject.send(.presentGlobalSearch)
case .markRoomAsUnread(let roomIdentifier):
Task {
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomIdentifier) else {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomIdentifier) else {
MXLog.error("Failed retrieving room for identifier: \(roomIdentifier)")
return
}
@@ -173,7 +173,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
case .markRoomAsRead(let roomIdentifier):
Task {
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomIdentifier) else {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomIdentifier) else {
MXLog.error("Failed retrieving room for identifier: \(roomIdentifier)")
return
}
@@ -367,7 +367,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
private func markRoomAsFavourite(_ roomID: String, isFavourite: Bool) async {
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
MXLog.error("Failed retrieving room for identifier: \(roomID)")
return
}
@@ -382,53 +382,47 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
private static let leaveRoomLoadingID = "LeaveRoomLoading"
private func startLeaveRoomProcess(roomId: String) {
private func startLeaveRoomProcess(roomID: String) {
Task {
defer {
userIndicatorController.retractIndicatorWithId(Self.leaveRoomLoadingID)
}
userIndicatorController.submitIndicator(UserIndicator(id: Self.leaveRoomLoadingID, type: .modal, title: L10n.commonLoading, persistent: true))
let room = await userSession.clientProxy.roomForIdentifier(roomId)
guard let room else {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
state.bindings.alertInfo = AlertInfo(id: UUID(), title: L10n.errorUnknown)
return
}
if room.isPublic {
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomId, isDM: room.isEncryptedOneToOneRoom, state: .public)
if roomProxy.isPublic {
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .public)
} else {
state.bindings.leaveRoomAlertItem = if room.joinedMembersCount > 1 {
LeaveRoomAlertItem(roomID: roomId, isDM: room.isEncryptedOneToOneRoom, state: .private)
state.bindings.leaveRoomAlertItem = if roomProxy.joinedMembersCount > 1 {
LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .private)
} else {
LeaveRoomAlertItem(roomID: roomId, isDM: room.isEncryptedOneToOneRoom, state: .empty)
LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .empty)
}
}
}
}
private func leaveRoom(roomId: String) {
Task {
defer {
userIndicatorController.retractIndicatorWithId(Self.leaveRoomLoadingID)
}
userIndicatorController.submitIndicator(UserIndicator(id: Self.leaveRoomLoadingID, type: .modal, title: L10n.commonLeavingRoom, persistent: true))
let room = await userSession.clientProxy.roomForIdentifier(roomId)
let result = await room?.leaveRoom()
switch result {
case .none, .some(.failure):
state.bindings.alertInfo = AlertInfo(id: UUID(), title: L10n.errorUnknown)
case .some(.success):
userIndicatorController.submitIndicator(UserIndicator(id: UUID().uuidString,
type: .toast,
title: L10n.commonCurrentUserLeftRoom,
iconName: "checkmark"))
actionsSubject.send(.roomLeft(roomIdentifier: roomId))
}
private func leaveRoom(roomID: String) async {
defer {
userIndicatorController.retractIndicatorWithId(Self.leaveRoomLoadingID)
}
userIndicatorController.submitIndicator(UserIndicator(id: Self.leaveRoomLoadingID, type: .modal, title: L10n.commonLeavingRoom, persistent: true))
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID),
case .success = await roomProxy.leaveRoom() else {
state.bindings.alertInfo = AlertInfo(id: UUID(), title: L10n.errorUnknown)
return
}
userIndicatorController.submitIndicator(UserIndicator(id: UUID().uuidString,
type: .toast,
title: L10n.commonCurrentUserLeftRoom,
iconName: "checkmark"))
actionsSubject.send(.roomLeft(roomIdentifier: roomID))
}
// MARK: Invites
@@ -440,7 +434,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true))
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
guard case let .invited(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
displayError()
return
}
@@ -478,7 +472,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true))
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
guard case let .invited(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
displayError()
return
}
@@ -31,7 +31,7 @@ enum InviteUsersScreenViewModelAction {
enum InviteUsersScreenRoomType {
case draft
case room(roomProxy: RoomProxyProtocol)
case room(roomProxy: JoinedRoomProxyProtocol)
}
struct InviteUsersScreenViewState: BindableState {
@@ -27,7 +27,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
private let userIndicatorController: UserIndicatorControllerProtocol
private var roomPreviewDetails: RoomPreviewDetails?
private var roomProxy: RoomProxyProtocol?
private var room: RoomProxyType?
private let actionsSubject: PassthroughSubject<JoinRoomScreenViewModelAction, Never> = .init()
var actionsPublisher: AnyPublisher<JoinRoomScreenViewModelAction, Never> {
@@ -89,8 +89,8 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
// See if we known about the room locally and, if so, have that
// take priority over the preview one.
if let roomProxy = await clientProxy.roomForIdentifier(roomID) {
self.roomProxy = roomProxy
if let room = await clientProxy.roomForIdentifier(roomID) {
self.room = room
await updateRoomDetails()
}
@@ -106,8 +106,20 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
}
private func updateRoomDetails() async {
var roomProxy: RoomProxyProtocol?
var inviter: RoomInviterDetails?
switch room {
case .joined(let joinedRoomProxy):
roomProxy = joinedRoomProxy
case .invited(let invitedRoomProxy):
inviter = await invitedRoomProxy.inviter.flatMap(RoomInviterDetails.init)
roomProxy = invitedRoomProxy
default:
break
}
let name = roomProxy?.name ?? roomPreviewDetails?.name
let inviter = await roomProxy?.inviter.flatMap(RoomInviterDetails.init)
state.roomDetails = JoinRoomScreenRoomDetails(name: name,
topic: roomProxy?.topic ?? roomPreviewDetails?.topic,
canonicalAlias: roomProxy?.canonicalAlias ?? roomPreviewDetails?.canonicalAlias,
@@ -119,9 +131,18 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
}
private func updateMode() {
if roomProxy?.membership == .invited || roomPreviewDetails?.isInvited ?? false { // Check invites first to show Accept/Decline buttons on public rooms.
// Check invites first to show Accept/Decline buttons on public rooms.
if case .invited = room {
state.mode = .invited
} else if roomProxy?.isPublic ?? false || roomPreviewDetails?.isPublic ?? false {
return
}
if roomPreviewDetails?.isInvited ?? false {
state.mode = .invited
return
}
if roomPreviewDetails?.isPublic ?? false {
state.mode = .join
} else if roomPreviewDetails?.canKnock ?? false, allowKnocking { // Knocking is not supported yet, the flag is purely for preview tests.
state.mode = .knock
@@ -180,7 +201,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true))
guard let roomProxy = await clientProxy.roomForIdentifier(roomID) else {
guard case let .invited(roomProxy) = room else {
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
return
}
@@ -19,7 +19,7 @@ import SwiftUI
struct MediaUploadPreviewScreenCoordinatorParameters {
let userIndicatorController: UserIndicatorControllerProtocol
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let mediaUploadingPreprocessor: MediaUploadingPreprocessor
let title: String?
let url: URL
@@ -22,7 +22,7 @@ typealias MediaUploadPreviewScreenViewModelType = StateStoreViewModel<MediaUploa
class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, MediaUploadPreviewScreenViewModelProtocol {
private let userIndicatorController: UserIndicatorControllerProtocol
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let mediaUploadingPreprocessor: MediaUploadingPreprocessor
private let url: URL
private var requestHandle: SendAttachmentJoinHandleProtocol? {
@@ -38,7 +38,7 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType,
}
init(userIndicatorController: UserIndicatorControllerProtocol,
roomProxy: RoomProxyProtocol,
roomProxy: JoinedRoomProxyProtocol,
mediaUploadingPreprocessor: MediaUploadingPreprocessor,
title: String?,
url: URL) {
@@ -124,7 +124,7 @@ private class PreviewItem: NSObject, QLPreviewItem {
struct MediaUploadPreviewScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = MediaUploadPreviewScreenViewModel(userIndicatorController: UserIndicatorControllerMock.default,
roomProxy: RoomProxyMock(),
roomProxy: JoinedRoomProxyMock(),
mediaUploadingPreprocessor: MediaUploadingPreprocessor(),
title: "some random file name",
url: URL.picturesDirectory)
@@ -118,7 +118,7 @@ class MessageForwardingScreenViewModel: MessageForwardingScreenViewModelType, Me
fatalError()
}
guard let targetRoomProxy = await clientProxy.roomForIdentifier(roomID) else {
guard case let .joined(targetRoomProxy) = await clientProxy.roomForIdentifier(roomID) else {
MXLog.error("Failed retrieving room to forward to with id: \(roomID)")
userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown))
return
@@ -18,7 +18,7 @@ import Combine
import SwiftUI
struct PinnedEventsTimelineScreenCoordinatorParameters {
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let timelineController: RoomTimelineControllerProtocol
let mediaProvider: MediaProviderProtocol
let mediaPlayerProvider: MediaPlayerProviderProtocol
@@ -81,7 +81,7 @@ struct PinnedEventsTimelineScreen_Previews: PreviewProvider, TestablePreview {
static let emptyTimelineViewModel: TimelineViewModel = {
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = []
return TimelineViewModel(roomProxy: RoomProxyMock(.init(name: "Preview room")),
return TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Preview room")),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -20,7 +20,7 @@ import SwiftUI
struct ReportContentScreenCoordinatorParameters {
let eventID: String
let senderID: String
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let clientProxy: ClientProxyProtocol
let userIndicatorController: UserIndicatorControllerProtocol
}
@@ -22,7 +22,7 @@ typealias ReportContentScreenViewModelType = StateStoreViewModel<ReportContentSc
class ReportContentScreenViewModel: ReportContentScreenViewModelType, ReportContentScreenViewModelProtocol {
private let eventID: String
private let senderID: String
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let clientProxy: ClientProxyProtocol
private let actionsSubject: PassthroughSubject<ReportContentScreenViewModelAction, Never> = .init()
@@ -30,7 +30,7 @@ class ReportContentScreenViewModel: ReportContentScreenViewModelType, ReportCont
actionsSubject.eraseToAnyPublisher()
}
init(eventID: String, senderID: String, roomProxy: RoomProxyProtocol, clientProxy: ClientProxyProtocol) {
init(eventID: String, senderID: String, roomProxy: JoinedRoomProxyProtocol, clientProxy: ClientProxyProtocol) {
self.eventID = eventID
self.senderID = senderID
self.roomProxy = roomProxy
@@ -77,7 +77,7 @@ struct ReportContentScreen: View {
struct ReportContentScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = ReportContentScreenViewModel(eventID: "",
senderID: "",
roomProxy: RoomProxyMock(.init()),
roomProxy: JoinedRoomProxyMock(.init()),
clientProxy: ClientProxyMock(.init()))
static var previews: some View {
@@ -20,7 +20,7 @@ import SwiftUI
struct RoomChangePermissionsScreenCoordinatorParameters {
let permissions: RoomPermissions
let permissionsGroup: RoomRolesAndPermissionsScreenPermissionsGroup
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let userIndicatorController: UserIndicatorControllerProtocol
let analytics: AnalyticsService
}
@@ -21,7 +21,7 @@ import SwiftUI
typealias RoomChangePermissionsScreenViewModelType = StateStoreViewModel<RoomChangePermissionsScreenViewState, RoomChangePermissionsScreenViewAction>
class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModelType, RoomChangePermissionsScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let analytics: AnalyticsService
@@ -32,7 +32,7 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel
init(currentPermissions: RoomPermissions,
group: RoomRolesAndPermissionsScreenPermissionsGroup,
roomProxy: RoomProxyProtocol,
roomProxy: JoinedRoomProxyProtocol,
userIndicatorController: UserIndicatorControllerProtocol,
analytics: AnalyticsService) {
self.roomProxy = roomProxy
@@ -86,7 +86,7 @@ struct RoomChangePermissionsScreen_Previews: PreviewProvider, TestablePreview {
static func makeViewModel(group: RoomRolesAndPermissionsScreenPermissionsGroup) -> RoomChangePermissionsScreenViewModel {
RoomChangePermissionsScreenViewModel(currentPermissions: .init(powerLevels: .mock),
group: group,
roomProxy: RoomProxyMock(.init()),
roomProxy: JoinedRoomProxyMock(.init()),
userIndicatorController: UserIndicatorControllerMock(),
analytics: ServiceLocator.shared.analytics)
}
@@ -19,7 +19,7 @@ import SwiftUI
struct RoomChangeRolesScreenCoordinatorParameters {
let mode: RoomMemberDetails.Role
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let mediaProvider: MediaProviderProtocol
let userIndicatorController: UserIndicatorControllerProtocol
let analytics: AnalyticsService
@@ -20,7 +20,7 @@ import SwiftUI
typealias RoomChangeRolesScreenViewModelType = StateStoreViewModel<RoomChangeRolesScreenViewState, RoomChangeRolesScreenViewAction>
class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomChangeRolesScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let analytics: AnalyticsService
@@ -30,7 +30,7 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh
}
init(mode: RoomMemberDetails.Role,
roomProxy: RoomProxyProtocol,
roomProxy: JoinedRoomProxyProtocol,
mediaProvider: MediaProviderProtocol,
userIndicatorController: UserIndicatorControllerProtocol,
analytics: AnalyticsService) {
@@ -130,7 +130,7 @@ struct RoomChangeRolesScreen_Previews: PreviewProvider, TestablePreview {
static func makeViewModel(mode: RoomMemberDetails.Role) -> RoomChangeRolesScreenViewModel {
RoomChangeRolesScreenViewModel(mode: mode,
roomProxy: RoomProxyMock(.init(members: .allMembersAsAdmin)),
roomProxy: JoinedRoomProxyMock(.init(members: .allMembersAsAdmin)),
mediaProvider: MockMediaProvider(),
userIndicatorController: UserIndicatorControllerMock(),
analytics: ServiceLocator.shared.analytics)
@@ -18,7 +18,7 @@ import Combine
import SwiftUI
struct RoomDetailsEditScreenCoordinatorParameters {
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let mediaProvider: MediaProviderProtocol
weak var navigationStackCoordinator: NavigationStackCoordinator?
let userIndicatorController: UserIndicatorControllerProtocol
@@ -21,7 +21,7 @@ typealias RoomDetailsEditScreenViewModelType = StateStoreViewModel<RoomDetailsEd
class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDetailsEditScreenViewModelProtocol {
private let actionsSubject: PassthroughSubject<RoomDetailsEditScreenViewModelAction, Never> = .init()
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let mediaPreprocessor: MediaUploadingPreprocessor = .init()
@@ -29,7 +29,7 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe
actionsSubject.eraseToAnyPublisher()
}
init(roomProxy: RoomProxyProtocol,
init(roomProxy: JoinedRoomProxyProtocol,
mediaProvider: MediaProviderProtocol,
userIndicatorController: UserIndicatorControllerProtocol) {
self.roomProxy = roomProxy
@@ -157,9 +157,9 @@ struct RoomDetailsEditScreen: View {
struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview {
static let editableViewModel = {
let roomProxy = RoomProxyMock(.init(id: "test_id",
name: "Room",
members: [.mockMeAdmin]))
let roomProxy = JoinedRoomProxyMock(.init(id: "test_id",
name: "Room",
members: [.mockMeAdmin]))
return RoomDetailsEditScreenViewModel(roomProxy: roomProxy,
mediaProvider: MockMediaProvider(),
@@ -167,9 +167,9 @@ struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview {
}()
static let readOnlyViewModel = {
let roomProxy = RoomProxyMock(.init(id: "test_id",
name: "Room",
members: [.mockAlice]))
let roomProxy = JoinedRoomProxyMock(.init(id: "test_id",
name: "Room",
members: [.mockAlice]))
return RoomDetailsEditScreenViewModel(roomProxy: roomProxy,
mediaProvider: MockMediaProvider(),
@@ -18,7 +18,7 @@ import Combine
import SwiftUI
struct RoomDetailsScreenCoordinatorParameters {
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let clientProxy: ClientProxyProtocol
let mediaProvider: MediaProviderProtocol
let analyticsService: AnalyticsService
@@ -20,7 +20,7 @@ import SwiftUI
typealias RoomDetailsScreenViewModelType = StateStoreViewModel<RoomDetailsScreenViewState, RoomDetailsScreenViewAction>
class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let clientProxy: ClientProxyProtocol
private let analyticsService: AnalyticsService
private let mediaProvider: MediaProviderProtocol
@@ -54,7 +54,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
actionsSubject.eraseToAnyPublisher()
}
init(roomProxy: RoomProxyProtocol,
init(roomProxy: JoinedRoomProxyProtocol,
clientProxy: ClientProxyProtocol,
mediaProvider: MediaProviderProtocol,
analyticsService: AnalyticsService,
@@ -311,20 +311,20 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
.mockBob,
.mockCharlie
]
let roomProxy = RoomProxyMock(.init(id: "room_a_id",
name: "Room A",
topic: """
Discussions about Element X iOS | https://github.com/vector-im/element-x-ios
Feature Status: https://github.com/vector-im/element-x-ios/issues/1225
App Store: https://apple.co/3r6LJHZ
TestFlight: https://testflight.apple.com/join/uZbeZCOi
""",
isDirect: false,
isEncrypted: true,
canonicalAlias: "#alias:domain.com",
members: members))
let roomProxy = JoinedRoomProxyMock(.init(id: "room_a_id",
name: "Room A",
topic: """
Discussions about Element X iOS | https://github.com/vector-im/element-x-ios
Feature Status: https://github.com/vector-im/element-x-ios/issues/1225
App Store: https://apple.co/3r6LJHZ
TestFlight: https://testflight.apple.com/join/uZbeZCOi
""",
isDirect: false,
isEncrypted: true,
canonicalAlias: "#alias:domain.com",
members: members))
var notificationSettingsProxyMockConfiguration = NotificationSettingsProxyMockConfiguration()
notificationSettingsProxyMockConfiguration.roomMode.isDefault = false
@@ -349,13 +349,13 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
.mockDan
]
let roomProxy = RoomProxyMock(.init(id: "dm_room_id",
name: "DM Room",
topic: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
isDirect: true,
isEncrypted: true,
canonicalAlias: "#alias:domain.com",
members: members))
let roomProxy = JoinedRoomProxyMock(.init(id: "dm_room_id",
name: "DM Room",
topic: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
isDirect: true,
isEncrypted: true,
canonicalAlias: "#alias:domain.com",
members: members))
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
let appSettings = AppSettings()
appSettings.pinningEnabled = true
@@ -378,11 +378,11 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
.mockBob,
.mockCharlie
]
let roomProxy = RoomProxyMock(.init(id: "simple_room_id",
name: "Room A",
isDirect: false,
isEncrypted: false,
members: members))
let roomProxy = JoinedRoomProxyMock(.init(id: "simple_room_id",
name: "Room A",
isDirect: false,
isEncrypted: false,
members: members))
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
let appSettings = AppSettings()
appSettings.pinningEnabled = true
@@ -19,7 +19,7 @@ import SwiftUI
struct RoomMemberDetailsScreenCoordinatorParameters {
let userID: String
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let clientProxy: ClientProxyProtocol
let mediaProvider: MediaProviderProtocol
let userIndicatorController: UserIndicatorControllerProtocol
@@ -20,7 +20,7 @@ import SwiftUI
typealias RoomMemberDetailsScreenViewModelType = StateStoreViewModel<RoomMemberDetailsScreenViewState, RoomMemberDetailsScreenViewAction>
class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, RoomMemberDetailsScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let clientProxy: ClientProxyProtocol
private let mediaProvider: MediaProviderProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
@@ -35,7 +35,7 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro
}
init(userID: String,
roomProxy: RoomProxyProtocol,
roomProxy: JoinedRoomProxyProtocol,
clientProxy: ClientProxyProtocol,
mediaProvider: MediaProviderProtocol,
userIndicatorController: UserIndicatorControllerProtocol,
@@ -143,7 +143,7 @@ struct RoomMemberDetailsScreen_Previews: PreviewProvider, TestablePreview {
}
static func makeViewModel(member: RoomMemberProxyMock) -> RoomMemberDetailsScreenViewModel {
let roomProxyMock = RoomProxyMock(.init(name: ""))
let roomProxyMock = JoinedRoomProxyMock(.init(name: ""))
roomProxyMock.getMemberUserIDReturnValue = .success(member)
let clientProxyMock = ClientProxyMock(.init())
@@ -19,7 +19,7 @@ import SwiftUI
struct RoomMembersListScreenCoordinatorParameters {
let mediaProvider: MediaProviderProtocol
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let userIndicatorController: UserIndicatorControllerProtocol
let analytics: AnalyticsService
}
@@ -20,7 +20,7 @@ import SwiftUI
typealias RoomMembersListScreenViewModelType = StateStoreViewModel<RoomMembersListScreenViewState, RoomMembersListScreenViewAction>
class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMembersListScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let analytics: AnalyticsService
@@ -33,7 +33,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
}
init(initialMode: RoomMembersListScreenMode = .members,
roomProxy: RoomProxyProtocol,
roomProxy: JoinedRoomProxyProtocol,
mediaProvider: MediaProviderProtocol,
userIndicatorController: UserIndicatorControllerProtocol,
analytics: AnalyticsService) {
@@ -108,7 +108,7 @@ struct RoomMembersListManageMemberSheetLive_Previews: PreviewProvider {
private extension RoomMembersListScreenViewModel {
static var mock: RoomMembersListScreenViewModel {
RoomMembersListScreenViewModel(initialMode: .members,
roomProxy: RoomProxyMock(.init(members: .allMembersAsAdmin)),
roomProxy: JoinedRoomProxyMock(.init(members: .allMembersAsAdmin)),
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
analytics: ServiceLocator.shared.analytics)
@@ -179,10 +179,10 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview {
}
return RoomMembersListScreenViewModel(initialMode: initialMode,
roomProxy: RoomProxyMock(.init(name: "Some room",
members: members,
ownUserID: ownUserID,
canUserInvite: false)),
roomProxy: JoinedRoomProxyMock(.init(name: "Some room",
members: members,
ownUserID: ownUserID,
canUserInvite: false)),
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
analytics: ServiceLocator.shared.analytics)
@@ -106,8 +106,8 @@ struct RoomMembersListMemberCell_Previews: PreviewProvider, TestablePreview {
.init(with: .init(userID: "@badavatar:matrix.org", avatarURL: .picturesDirectory, membership: .ban))
]
static let viewModel = RoomMembersListScreenViewModel(roomProxy: RoomProxyMock(.init(name: "Some room",
members: members)),
static let viewModel = RoomMembersListScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Some room",
members: members)),
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
analytics: ServiceLocator.shared.analytics)
@@ -20,7 +20,7 @@ import SwiftUI
struct RoomNotificationSettingsScreenCoordinatorParameters {
weak var navigationStackCoordinator: NavigationStackCoordinator?
let notificationSettingsProxy: NotificationSettingsProxyProtocol
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let displayAsUserDefinedRoomSettings: Bool
}
@@ -22,7 +22,7 @@ typealias RoomNotificationSettingsScreenViewModelType = StateStoreViewModel<Room
class RoomNotificationSettingsScreenViewModel: RoomNotificationSettingsScreenViewModelType, RoomNotificationSettingsScreenViewModelProtocol {
private let actionsSubject: PassthroughSubject<RoomNotificationSettingsScreenViewModelAction, Never> = .init()
private let notificationSettingsProxy: NotificationSettingsProxyProtocol
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
// periphery:ignore - cancellable tasks cancel when reassigned
@CancellableTask private var fetchNotificationSettingsTask: Task<Void, Error>?
@@ -31,7 +31,7 @@ class RoomNotificationSettingsScreenViewModel: RoomNotificationSettingsScreenVie
actionsSubject.eraseToAnyPublisher()
}
init(notificationSettingsProxy: NotificationSettingsProxyProtocol, roomProxy: RoomProxyProtocol, displayAsUserDefinedRoomSettings: Bool) {
init(notificationSettingsProxy: NotificationSettingsProxyProtocol, roomProxy: JoinedRoomProxyProtocol, displayAsUserDefinedRoomSettings: Bool) {
let bindings = RoomNotificationSettingsScreenViewStateBindings()
self.notificationSettingsProxy = notificationSettingsProxy
self.roomProxy = roomProxy
@@ -42,7 +42,7 @@ struct RoomNotificationSettingsCustomSectionView_Previews: PreviewProvider, Test
static let viewModel = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(.init(name: "Room", isEncrypted: true))
let roomProxy = JoinedRoomProxyMock(.init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -52,7 +52,7 @@ struct RoomNotificationSettingsCustomSectionView_Previews: PreviewProvider, Test
static let viewModelUnencrypted = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(.init(name: "Room", isEncrypted: false))
let roomProxy = JoinedRoomProxyMock(.init(name: "Room", isEncrypted: false))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -83,7 +83,7 @@ struct RoomNotificationSettingsScreen_Previews: PreviewProvider, TestablePreview
static let viewModel = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .mentionsAndKeywordsOnly, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(.init(name: "Room", isEncrypted: true))
let roomProxy = JoinedRoomProxyMock(.init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -93,7 +93,7 @@ struct RoomNotificationSettingsScreen_Previews: PreviewProvider, TestablePreview
static let viewModelCustom = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(.init(name: "Room", isEncrypted: true))
let roomProxy = JoinedRoomProxyMock(.init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -52,7 +52,7 @@ struct RoomNotificationSettingsUserDefinedScreen_Previews: PreviewProvider, Test
static let viewModel = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .mentionsAndKeywordsOnly, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(.init(name: "Room", isEncrypted: true))
let roomProxy = JoinedRoomProxyMock(.init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -62,7 +62,7 @@ struct RoomNotificationSettingsUserDefinedScreen_Previews: PreviewProvider, Test
static let viewModelUnencrypted = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .mentionsAndKeywordsOnly, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(.init(name: "Room", isEncrypted: false))
let roomProxy = JoinedRoomProxyMock(.init(name: "Room", isEncrypted: false))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -124,7 +124,7 @@ struct RoomPollsHistoryScreen_Previews: PreviewProvider, TestablePreview {
static let viewModelEmpty: RoomPollsHistoryScreenViewModel = {
let roomTimelineController = MockRoomTimelineController()
roomTimelineController.timelineItems = []
let roomProxyMockConfiguration = RoomProxyMockConfiguration(name: "Polls")
let roomProxyMockConfiguration = JoinedRoomProxyMockConfiguration(name: "Polls")
let viewModel = RoomPollsHistoryScreenViewModel(pollInteractionHandler: PollInteractionHandlerMock(),
roomTimelineController: roomTimelineController,
userIndicatorController: UserIndicatorControllerMock())
@@ -146,7 +146,7 @@ struct RoomPollsHistoryScreen_Previews: PreviewProvider, TestablePreview {
roomTimelineController.timelineItemsTimestamp[item.id] = date
}
let roomProxyMockConfiguration = RoomProxyMockConfiguration(name: "Polls", timelineStartReached: true)
let roomProxyMockConfiguration = JoinedRoomProxyMockConfiguration(name: "Polls", timelineStartReached: true)
let viewModel = RoomPollsHistoryScreenViewModel(pollInteractionHandler: PollInteractionHandlerMock(),
roomTimelineController: roomTimelineController,
userIndicatorController: UserIndicatorControllerMock())
@@ -18,7 +18,7 @@ import Combine
import SwiftUI
struct RoomRolesAndPermissionsScreenCoordinatorParameters {
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
let userIndicatorController: UserIndicatorControllerProtocol
let analytics: AnalyticsService
}
@@ -20,7 +20,7 @@ import SwiftUI
typealias RoomRolesAndPermissionsScreenViewModelType = StateStoreViewModel<RoomRolesAndPermissionsScreenViewState, RoomRolesAndPermissionsScreenViewAction>
class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewModelType, RoomRolesAndPermissionsScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let analytics: AnalyticsService
@@ -29,7 +29,7 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
actionsSubject.eraseToAnyPublisher()
}
init(initialPermissions: RoomPermissions? = nil, roomProxy: RoomProxyProtocol, userIndicatorController: UserIndicatorControllerProtocol, analytics: AnalyticsService) {
init(initialPermissions: RoomPermissions? = nil, roomProxy: JoinedRoomProxyProtocol, userIndicatorController: UserIndicatorControllerProtocol, analytics: AnalyticsService) {
self.roomProxy = roomProxy
self.userIndicatorController = userIndicatorController
self.analytics = analytics
@@ -127,7 +127,7 @@ struct RoomRolesAndPermissionsScreen: View {
struct RoomRolesAndPermissionsScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = RoomRolesAndPermissionsScreenViewModel(initialPermissions: RoomPermissions(powerLevels: .mock),
roomProxy: RoomProxyMock(.init(members: .allMembersAsAdmin)),
roomProxy: JoinedRoomProxyMock(.init(members: .allMembersAsAdmin)),
userIndicatorController: UserIndicatorControllerMock(),
analytics: ServiceLocator.shared.analytics)
static var previews: some View {
@@ -22,13 +22,13 @@ private enum SuggestionTriggerPattern: Character {
}
final class CompletionSuggestionService: CompletionSuggestionServiceProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private var canMentionAllUsers = false
private(set) var suggestionsPublisher: AnyPublisher<[SuggestionItem], Never> = Empty().eraseToAnyPublisher()
private let suggestionTriggerSubject = CurrentValueSubject<SuggestionTrigger?, Never>(nil)
init(roomProxy: RoomProxyProtocol) {
init(roomProxy: JoinedRoomProxyProtocol) {
self.roomProxy = roomProxy
suggestionsPublisher = suggestionTriggerSubject
@@ -20,7 +20,7 @@ import SwiftUI
import WysiwygComposer
struct RoomScreenCoordinatorParameters {
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
var focussedEventID: String?
let timelineController: RoomTimelineControllerProtocol
let mediaProvider: MediaProviderProtocol
@@ -22,7 +22,7 @@ import SwiftUI
typealias RoomScreenViewModelType = StateStoreViewModel<RoomScreenViewState, RoomScreenViewAction>
class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let appMediator: AppMediatorProtocol
private let appSettings: AppSettings
private let analyticsService: AnalyticsService
@@ -51,7 +51,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
}
init(roomProxy: RoomProxyProtocol,
init(roomProxy: JoinedRoomProxyProtocol,
mediaProvider: MediaProviderProtocol,
appMediator: AppMediatorProtocol,
appSettings: AppSettings,
@@ -183,7 +183,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
extension RoomScreenViewModel {
static func mock(roomProxyMock: RoomProxyMock) -> RoomScreenViewModel {
static func mock(roomProxyMock: JoinedRoomProxyMock) -> RoomScreenViewModel {
RoomScreenViewModel(roomProxy: roomProxyMock,
mediaProvider: MockMediaProvider(),
appMediator: AppMediatorMock.default,
@@ -210,9 +210,9 @@ struct RoomScreen: View {
// MARK: - Previews
struct RoomScreen_Previews: PreviewProvider, TestablePreview {
static let roomProxyMock = RoomProxyMock(.init(id: "stable_id",
name: "Preview room",
hasOngoingCall: true))
static let roomProxyMock = JoinedRoomProxyMock(.init(id: "stable_id",
name: "Preview room",
hasOngoingCall: true))
static let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock)
static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
@@ -57,7 +57,7 @@ final class NotificationSettingsEditScreenCoordinator: CoordinatorProtocol {
// MARK: - Private
private func presentRoomNotificationSettings(roomID: String) async {
guard let roomProxy = await parameters.userSession.clientProxy.roomForIdentifier(roomID) else { return }
guard case let .joined(roomProxy) = await parameters.userSession.clientProxy.roomForIdentifier(roomID) else { return }
let roomNotificationSettingsParameters = RoomNotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator,
notificationSettingsProxy: parameters.notificationSettings,
@@ -138,7 +138,7 @@ class NotificationSettingsEditScreenViewModel: NotificationSettingsEditScreenVie
var roomsWithUserDefinedMode: [NotificationSettingsEditScreenRoom] = []
for roomSummary in filteredRoomsSummary {
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomSummary.id) else { continue }
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomSummary.id) else { continue }
// `isOneToOneRoom` here is not the same as `isDirect` on the room. From the point of view of the push rule, a one-to-one room is a room with exactly two active members.
let isOneToOneRoom = roomProxy.activeMembersCount == 2
// display only the rooms we're interested in
@@ -35,7 +35,7 @@ enum TimelineInteractionHandlerAction {
@MainActor
class TimelineInteractionHandler {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let timelineController: RoomTimelineControllerProtocol
private let mediaProvider: MediaProviderProtocol
private let mediaPlayerProvider: MediaPlayerProviderProtocol
@@ -60,7 +60,7 @@ class TimelineInteractionHandler {
private var resumeVoiceMessagePlaybackAfterScrubbing = false
init(roomProxy: RoomProxyProtocol,
init(roomProxy: JoinedRoomProxyProtocol,
timelineController: RoomTimelineControllerProtocol,
mediaProvider: MediaProviderProtocol,
mediaPlayerProvider: MediaPlayerProviderProtocol,
@@ -29,7 +29,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
static let toastErrorID = "RoomScreenToastError"
}
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let timelineController: RoomTimelineControllerProtocol
private let mediaPlayerProvider: MediaPlayerProviderProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
@@ -49,7 +49,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
private var paginateBackwardsTask: Task<Void, Never>?
private var paginateForwardsTask: Task<Void, Never>?
init(roomProxy: RoomProxyProtocol,
init(roomProxy: JoinedRoomProxyProtocol,
focussedEventID: String? = nil,
timelineController: RoomTimelineControllerProtocol,
mediaProvider: MediaProviderProtocol,
@@ -819,7 +819,7 @@ private extension RoomProxyProtocol {
// MARK: - Mocks
extension TimelineViewModel {
static let mock = TimelineViewModel(roomProxy: RoomProxyMock(.init(name: "Preview room")),
static let mock = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Preview room")),
focussedEventID: nil,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
@@ -51,7 +51,7 @@ struct ReadReceiptsSummaryView_Previews: PreviewProvider, TestablePreview {
.mockCharlie,
.mockDan
]
let roomProxyMock = RoomProxyMock(.init(name: "Room", members: members))
let roomProxyMock = JoinedRoomProxyMock(.init(name: "Room", members: members))
let mock = TimelineViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
@@ -90,7 +90,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview {
.mockMe
]
static let viewModel = TimelineViewModel(roomProxy: RoomProxyMock(.init(name: "Test", members: members)),
static let viewModel = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Test", members: members)),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -93,7 +93,7 @@ struct HighlightedTimelineItemModifier_Previews: PreviewProvider, TestablePrevie
/// A preview that allows quick testing of the highlight appearance across various timeline scenarios.
struct HighlightedTimelineItemTimeline_Previews: PreviewProvider {
static let roomProxyMock = RoomProxyMock(.init(name: "Preview room"))
static let roomProxyMock = JoinedRoomProxyMock(.init(name: "Preview room"))
static let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock)
static let focussedEventID = "RoomTimelineItemFixtures.default.5"
static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock,
@@ -79,8 +79,8 @@ struct TimelineView: UIViewControllerRepresentable {
// MARK: - Previews
struct TimelineView_Previews: PreviewProvider, TestablePreview {
static let roomProxyMock = RoomProxyMock(.init(id: "stable_id",
name: "Preview room"))
static let roomProxyMock = JoinedRoomProxyMock(.init(id: "stable_id",
name: "Preview room"))
static let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock)
static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
@@ -443,23 +443,13 @@ class ClientProxy: ClientProxyProtocol {
return result
}
func roomForIdentifier(_ identifier: String) async -> RoomProxyProtocol? {
guard let roomListService else {
MXLog.error("Failed retrieving room, room list service not set up")
return nil
}
func roomForIdentifier(_ identifier: String) async -> RoomProxyType? {
// Try fetching the room from the cold cache (if available) first
var (roomListItem, room) = await roomTupleForIdentifier(identifier)
if let roomListItem, let room {
return await RoomProxy(roomListService: roomListService,
roomListItem: roomListItem,
room: room)
if let room = await buildRoomForIdentifier(identifier) {
return room
}
// Else wait for the visible rooms list to go into fully loaded
guard let roomSummaryProvider else {
MXLog.error("Rooms summary provider not setup yet")
return nil
@@ -469,21 +459,7 @@ class ClientProxy: ClientProxyProtocol {
_ = await roomSummaryProvider.statePublisher.values.first(where: { $0.isLoaded })
}
(roomListItem, room) = await roomTupleForIdentifier(identifier)
guard let roomListItem else {
MXLog.error("Invalid roomListItem for identifier \(identifier)")
return nil
}
guard let room else {
MXLog.error("Invalid roomListItem fullRoom for identifier \(identifier)")
return nil
}
return await RoomProxy(roomListService: roomListService,
roomListItem: roomListItem,
room: room)
return await buildRoomForIdentifier(identifier)
}
func roomPreviewForIdentifier(_ identifier: String, via: [String]) async -> Result<RoomPreviewDetails, ClientProxyError> {
@@ -703,9 +679,9 @@ class ClientProxy: ClientProxyProtocol {
var users: OrderedSet<UserProfileProxy> = []
for roomID in roomIdentifiers {
guard let room = await roomForIdentifier(roomID),
room.isDirect,
let members = await room.members() else {
guard case let .joined(roomProxy) = await roomForIdentifier(roomID),
roomProxy.isDirect,
let members = await roomProxy.members() else {
continue
}
@@ -868,19 +844,46 @@ class ClientProxy: ClientProxyProtocol {
return .exclude(eventTypes: stateEventFilters.map { FilterTimelineEventType.state(eventType: $0) })
}()
private func roomTupleForIdentifier(_ identifier: String) async -> (RoomListItem?, Room?) {
do {
let roomListItem = try roomListService?.room(roomId: identifier)
if roomListItem?.isTimelineInitialized() == false {
try await roomListItem?.initTimeline(eventTypeFilter: eventFilters, internalIdPrefix: nil)
private func buildRoomForIdentifier(_ identifier: String) async -> RoomProxyType? {
guard let roomListService else {
MXLog.error("Failed retrieving room, room list service not set up")
return nil
}
guard let roomListItem = try? roomListService.room(roomId: identifier) else {
MXLog.error("Failed retrieving room, invalid room list item")
return nil
}
if roomListItem.isTimelineInitialized() == false {
do {
try await roomListItem.initTimeline(eventTypeFilter: eventFilters, internalIdPrefix: nil)
} catch {
MXLog.error("Failed initializing room timeline with error: \(error)")
return nil
}
}
guard let room = try? roomListItem.fullRoom() else {
MXLog.error("Failed retrieving room, invalid room list item full room")
return nil
}
switch room.membership() {
case .invited:
return .invited(InvitedRoomProxy(roomListItem: roomListItem,
room: room))
case .joined:
guard let roomProxy = await JoinedRoomProxy(roomListService: roomListService,
roomListItem: roomListItem,
room: room) else {
return nil
}
let fullRoom = try roomListItem?.fullRoom()
return (roomListItem, fullRoom)
} catch {
MXLog.error("Failed retrieving/initialising room with identifier: \(identifier)")
return (nil, nil)
return .joined(roomProxy)
case .left:
return .left
}
}
@@ -146,7 +146,7 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
func uploadMedia(_ media: MediaInfo) async -> Result<String, ClientProxyError>
func roomForIdentifier(_ identifier: String) async -> RoomProxyProtocol?
func roomForIdentifier(_ identifier: String) async -> RoomProxyType?
func roomPreviewForIdentifier(_ identifier: String, via: [String]) async -> Result<RoomPreviewDetails, ClientProxyError>
@@ -19,11 +19,11 @@ import Foundation
import MatrixRustSDK
final class ComposerDraftService: ComposerDraftServiceProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let timelineItemfactory: RoomTimelineItemFactoryProtocol
private var volatileDraft: ComposerDraftProxy?
init(roomProxy: RoomProxyProtocol, timelineItemfactory: RoomTimelineItemFactoryProtocol) {
init(roomProxy: JoinedRoomProxyProtocol, timelineItemfactory: RoomTimelineItemFactoryProtocol) {
self.roomProxy = roomProxy
self.timelineItemfactory = timelineItemfactory
}
@@ -25,7 +25,7 @@ private enum GenericCallLinkQueryParameters {
struct ElementCallConfiguration {
enum Kind {
case genericCallLink(URL)
case roomCall(roomProxy: RoomProxyProtocol,
case roomCall(roomProxy: JoinedRoomProxyProtocol,
clientProxy: ClientProxyProtocol,
clientID: String,
elementCallBaseURL: URL,
@@ -62,7 +62,7 @@ struct ElementCallConfiguration {
}
/// Creates a configuration for an internal room call.
init(roomProxy: RoomProxyProtocol,
init(roomProxy: JoinedRoomProxyProtocol,
clientProxy: ClientProxyProtocol,
clientID: String,
elementCallBaseURL: URL,
@@ -276,7 +276,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
return
}
guard let roomProxy = await clientProxy.roomForIdentifier(incomingCallID.roomID) else {
guard case let .joined(roomProxy) = await clientProxy.roomForIdentifier(incomingCallID.roomID) else {
return
}
@@ -18,9 +18,9 @@ import Foundation
class PollInteractionHandler: PollInteractionHandlerProtocol {
let analyticsService: AnalyticsService
let roomProxy: RoomProxyProtocol
let roomProxy: JoinedRoomProxyProtocol
init(analyticsService: AnalyticsService, roomProxy: RoomProxyProtocol) {
init(analyticsService: AnalyticsService, roomProxy: JoinedRoomProxyProtocol) {
self.analyticsService = analyticsService
self.roomProxy = roomProxy
}
@@ -0,0 +1,111 @@
//
// Copyright 2024 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
import MatrixRustSDK
import UIKit
class InvitedRoomProxy: InvitedRoomProxyProtocol {
private let roomListItem: RoomListItemProtocol
private let room: RoomProtocol
// A room identifier is constant and lazy stops it from being fetched
// multiple times over FFI
lazy var id: String = room.id()
var canonicalAlias: String? {
room.canonicalAlias()
}
var ownUserID: String {
room.ownUserId()
}
var name: String? {
roomListItem.displayName()
}
var topic: String? {
room.topic()
}
var avatarURL: URL? {
roomListItem.avatarUrl().flatMap(URL.init(string:))
}
var avatar: RoomAvatar {
if isDirect, avatarURL == nil {
let heroes = room.heroes()
if heroes.count == 1 {
return .heroes(heroes.map(UserProfileProxy.init))
}
}
return .room(id: id, name: name, avatarURL: avatarURL)
}
var isDirect: Bool {
room.isDirect()
}
var isPublic: Bool {
room.isPublic()
}
var isSpace: Bool {
room.isSpace()
}
var joinedMembersCount: Int {
Int(room.joinedMembersCount())
}
var activeMembersCount: Int {
Int(room.activeMembersCount())
}
var inviter: RoomMemberProxyProtocol? {
get async {
await (try? roomListItem.roomInfo().inviter).map(RoomMemberProxy.init)
}
}
init(roomListItem: RoomListItemProtocol,
room: RoomProtocol) {
self.roomListItem = roomListItem
self.room = room
}
func acceptInvitation() async -> Result<Void, RoomProxyError> {
do {
try await room.join()
return .success(())
} catch {
MXLog.error("Failed accepting invitation with error: \(error)")
return .failure(.sdkError(error))
}
}
func rejectInvitation() async -> Result<Void, RoomProxyError> {
do {
return try await .success(room.leave())
} catch {
MXLog.error("Failed rejecting invitiation with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -19,7 +19,7 @@ import Foundation
import MatrixRustSDK
import UIKit
class RoomProxy: RoomProxyProtocol {
class JoinedRoomProxy: JoinedRoomProxyProtocol {
private let roomListService: RoomListServiceProtocol
private let roomListItem: RoomListItemProtocol
private let room: RoomProtocol
@@ -77,13 +77,19 @@ class RoomProxy: RoomProxyProtocol {
typingMembersSubject.asCurrentValuePublisher()
}
private let actionsSubject = PassthroughSubject<RoomProxyAction, Never>()
var actionsPublisher: AnyPublisher<RoomProxyAction, Never> {
private let actionsSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
var actionsPublisher: AnyPublisher<JoinedRoomProxyAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
// A room identifier is constant and lazy stops it from being fetched
// multiple times over FFI
lazy var id: String = room.id()
var canonicalAlias: String? {
room.canonicalAlias()
}
var ownUserID: String {
room.ownUserId()
}
@@ -96,14 +102,20 @@ class RoomProxy: RoomProxyProtocol {
room.topic()
}
var membership: Membership {
room.membership()
var avatarURL: URL? {
roomListItem.avatarUrl().flatMap(URL.init(string:))
}
var inviter: RoomMemberProxyProtocol? {
get async {
await (try? roomListItem.roomInfo().inviter).map(RoomMemberProxy.init)
var avatar: RoomAvatar {
if isDirect, avatarURL == nil {
let heroes = room.heroes()
if heroes.count == 1 {
return .heroes(heroes.map(UserProfileProxy.init))
}
}
return .room(id: id, name: name, avatarURL: avatarURL)
}
var isDirect: Bool {
@@ -118,6 +130,14 @@ class RoomProxy: RoomProxyProtocol {
room.isSpace()
}
var joinedMembersCount: Int {
Int(room.joinedMembersCount())
}
var activeMembersCount: Int {
Int(room.activeMembersCount())
}
var isEncrypted: Bool {
(try? room.isEncrypted()) ?? false
}
@@ -145,34 +165,6 @@ class RoomProxy: RoomProxyProtocol {
room.activeRoomCallParticipants()
}
var canonicalAlias: String? {
room.canonicalAlias()
}
var avatarURL: URL? {
roomListItem.avatarUrl().flatMap(URL.init(string:))
}
var avatar: RoomAvatar {
if isDirect, avatarURL == nil {
let heroes = room.heroes()
if heroes.count == 1 {
return .heroes(heroes.map(UserProfileProxy.init))
}
}
return .room(id: id, name: name, avatarURL: avatarURL)
}
var joinedMembersCount: Int {
Int(room.joinedMembersCount())
}
var activeMembersCount: Int {
Int(room.activeMembersCount())
}
init?(roomListService: RoomListServiceProtocol,
roomListItem: RoomListItemProtocol,
room: RoomProtocol) async {
@@ -315,25 +307,6 @@ class RoomProxy: RoomProxyProtocol {
}
}
func rejectInvitation() async -> Result<Void, RoomProxyError> {
do {
return try await .success(room.leave())
} catch {
MXLog.error("Failed rejecting invitiation with error: \(error)")
return .failure(.sdkError(error))
}
}
func acceptInvitation() async -> Result<Void, RoomProxyError> {
do {
try await room.join()
return .success(())
} catch {
MXLog.error("Failed accepting invitation with error: \(error)")
return .failure(.sdkError(error))
}
}
func invite(userID: String) async -> Result<Void, RoomProxyError> {
do {
MXLog.info("Inviting user \(userID)")
@@ -26,46 +26,62 @@ enum RoomProxyError: Error {
case eventNotFound
}
enum RoomProxyAction {
case roomInfoUpdate
enum RoomProxyType {
case joined(JoinedRoomProxyProtocol)
case invited(InvitedRoomProxyProtocol)
case left
}
// sourcery: AutoMockable
protocol RoomProxyProtocol {
var id: String { get }
var isDirect: Bool { get }
var isPublic: Bool { get }
var isSpace: Bool { get }
var isEncrypted: Bool { get }
var isFavourite: Bool { get async }
var pinnedEventIDs: Set<String> { get async }
var membership: Membership { get }
var inviter: RoomMemberProxyProtocol? { get async }
var hasOngoingCall: Bool { get }
var activeRoomCallParticipants: [String] { get }
var canonicalAlias: String? { get }
var ownUserID: String { get }
var name: String? { get }
var topic: String? { get }
/// The room's avatar info for use in a ``RoomAvatarImage``.
var avatar: RoomAvatar { get }
/// The room's avatar URL. Use this for editing and favour ``avatar`` for display.
var avatarURL: URL? { get }
var isPublic: Bool { get }
var isDirect: Bool { get }
var isSpace: Bool { get }
var joinedMembersCount: Int { get }
var activeMembersCount: Int { get }
}
// sourcery: AutoMockable
protocol InvitedRoomProxyProtocol: RoomProxyProtocol {
var inviter: RoomMemberProxyProtocol? { get async }
func rejectInvitation() async -> Result<Void, RoomProxyError>
func acceptInvitation() async -> Result<Void, RoomProxyError>
}
enum JoinedRoomProxyAction {
case roomInfoUpdate
}
// sourcery: AutoMockable
protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
var isEncrypted: Bool { get }
var isFavourite: Bool { get async }
var pinnedEventIDs: Set<String> { get async }
var hasOngoingCall: Bool { get }
var activeRoomCallParticipants: [String] { get }
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> { get }
var typingMembersPublisher: CurrentValuePublisher<[String], Never> { get }
var joinedMembersCount: Int { get }
var activeMembersCount: Int { get }
var actionsPublisher: AnyPublisher<RoomProxyAction, Never> { get }
var actionsPublisher: AnyPublisher<JoinedRoomProxyAction, Never> { get }
var timeline: TimelineProxyProtocol { get }
@@ -87,10 +103,6 @@ protocol RoomProxyProtocol {
func getMember(userID: String) async -> Result<RoomMemberProxyProtocol, RoomProxyError>
func rejectInvitation() async -> Result<Void, RoomProxyError>
func acceptInvitation() async -> Result<Void, RoomProxyError>
func invite(userID: String) async -> Result<Void, RoomProxyError>
func setName(_ name: String) async -> Result<Void, RoomProxyError>
@@ -155,7 +167,7 @@ protocol RoomProxyProtocol {
func clearDraft() async -> Result<Void, RoomProxyError>
}
extension RoomProxyProtocol {
extension JoinedRoomProxyProtocol {
var details: RoomDetails {
RoomDetails(id: id,
name: name,
@@ -26,7 +26,7 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
/// An array of timeline items that will be appended in order when ``simulateIncomingItems()`` is called.
var incomingItems: [RoomTimelineItemProtocol] = []
var roomProxy: RoomProxyProtocol?
var roomProxy: JoinedRoomProxyProtocol?
var roomID: String { roomProxy?.id ?? "MockRoomIdentifier" }
let callbacks = PassthroughSubject<RoomTimelineControllerCallback, Never>()
@@ -20,7 +20,7 @@ import MatrixRustSDK
import UIKit
class RoomTimelineController: RoomTimelineControllerProtocol {
private let roomProxy: RoomProxyProtocol
private let roomProxy: JoinedRoomProxyProtocol
private let liveTimelineProvider: RoomTimelineProviderProtocol
private let timelineItemFactory: RoomTimelineItemFactoryProtocol
private let appSettings: AppSettings
@@ -41,7 +41,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
roomProxy.id
}
init(roomProxy: RoomProxyProtocol,
init(roomProxy: JoinedRoomProxyProtocol,
timelineProxy: TimelineProxyProtocol,
initialFocussedEventID: String?,
timelineItemFactory: RoomTimelineItemFactoryProtocol,
@@ -17,7 +17,7 @@
import Foundation
struct RoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol {
func buildRoomTimelineController(roomProxy: RoomProxyProtocol,
func buildRoomTimelineController(roomProxy: JoinedRoomProxyProtocol,
initialFocussedEventID: String?,
timelineItemFactory: RoomTimelineItemFactoryProtocol) -> RoomTimelineControllerProtocol {
RoomTimelineController(roomProxy: roomProxy,
@@ -27,7 +27,7 @@ struct RoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol {
appSettings: ServiceLocator.shared.settings)
}
func buildRoomPinnedTimelineController(roomProxy: RoomProxyProtocol,
func buildRoomPinnedTimelineController(roomProxy: JoinedRoomProxyProtocol,
timelineItemFactory: RoomTimelineItemFactoryProtocol) async -> RoomTimelineControllerProtocol? {
guard let pinnedEventsTimeline = await roomProxy.pinnedEventsTimeline else {
return nil
@@ -18,10 +18,10 @@ import Foundation
@MainActor
protocol RoomTimelineControllerFactoryProtocol {
func buildRoomTimelineController(roomProxy: RoomProxyProtocol,
func buildRoomTimelineController(roomProxy: JoinedRoomProxyProtocol,
initialFocussedEventID: String?,
timelineItemFactory: RoomTimelineItemFactoryProtocol) -> RoomTimelineControllerProtocol
func buildRoomPinnedTimelineController(roomProxy: RoomProxyProtocol,
func buildRoomPinnedTimelineController(roomProxy: JoinedRoomProxyProtocol,
timelineItemFactory: RoomTimelineItemFactoryProtocol) async -> RoomTimelineControllerProtocol?
}
@@ -154,7 +154,7 @@ class VoiceMessageRecorder: VoiceMessageRecorderProtocol {
return .success(waveformData)
}
func sendVoiceMessage(inRoom roomProxy: RoomProxyProtocol, audioConverter: AudioConverterProtocol) async -> Result<Void, VoiceMessageRecorderError> {
func sendVoiceMessage(inRoom roomProxy: JoinedRoomProxyProtocol, audioConverter: AudioConverterProtocol) async -> Result<Void, VoiceMessageRecorderError> {
guard let url = audioRecorder.audioFileURL else {
return .failure(VoiceMessageRecorderError.missingRecordingFile)
}
@@ -47,7 +47,7 @@ protocol VoiceMessageRecorderProtocol {
func seekPlayback(to progress: Double) async
func deleteRecording() async
func sendVoiceMessage(inRoom roomProxy: RoomProxyProtocol, audioConverter: AudioConverterProtocol) async -> Result<Void, VoiceMessageRecorderError>
func sendVoiceMessage(inRoom roomProxy: JoinedRoomProxyProtocol, audioConverter: AudioConverterProtocol) async -> Result<Void, VoiceMessageRecorderError>
}
// sourcery: AutoMockable
@@ -248,7 +248,7 @@ class MockScreen: Identifiable {
return navigationStackCoordinator
case .roomPlainNoAvatar:
let navigationStackCoordinator = NavigationStackCoordinator()
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Some room name", avatarURL: nil)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Some room name", avatarURL: nil)),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -265,7 +265,7 @@ class MockScreen: Identifiable {
let navigationStackCoordinator = NavigationStackCoordinator()
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.smallChunk
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -282,7 +282,7 @@ class MockScreen: Identifiable {
let navigationStackCoordinator = NavigationStackCoordinator()
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.default
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -299,7 +299,7 @@ class MockScreen: Identifiable {
let navigationStackCoordinator = NavigationStackCoordinator()
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.smallChunkWithReadReceipts
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -319,7 +319,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.smallChunk
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.singleMessageChunk]
timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage]
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Small timeline", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -339,7 +339,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController(listenForSignals: true)
timelineController.timelineItems = RoomTimelineItemFixtures.smallChunk
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk]
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Small timeline, paginating", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline, paginating", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -359,7 +359,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController(listenForSignals: true)
timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk]
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -380,7 +380,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk]
timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage]
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -400,7 +400,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController(listenForSignals: true)
timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk
timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage]
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -419,7 +419,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.permalinkChunk
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Timeline highlight", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Timeline highlight", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -452,7 +452,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.disclosedPolls
timelineController.incomingItems = []
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -472,7 +472,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.undisclosedPolls
timelineController.incomingItems = []
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -492,7 +492,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.outgoingPolls
timelineController.incomingItems = []
let parameters = RoomScreenCoordinatorParameters(roomProxy: RoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)),
let parameters = RoomScreenCoordinatorParameters(roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -546,7 +546,7 @@ class MockScreen: Identifiable {
let navigationStackCoordinator = NavigationStackCoordinator()
let members: [RoomMemberProxyMock] = [.mockInvitedAlice, .mockBob, .mockCharlie]
let coordinator = RoomMembersListScreenCoordinator(parameters: .init(mediaProvider: MockMediaProvider(),
roomProxy: RoomProxyMock(.init(name: "test", members: members)),
roomProxy: JoinedRoomProxyMock(.init(name: "test", members: members)),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
analytics: ServiceLocator.shared.analytics))
navigationStackCoordinator.setRootCoordinator(coordinator)
@@ -554,7 +554,7 @@ class MockScreen: Identifiable {
case .roomRolesAndPermissionsFlow:
let navigationStackCoordinator = NavigationStackCoordinator()
navigationStackCoordinator.setRootCoordinator(BlankFormCoordinator())
let coordinator = RoomRolesAndPermissionsFlowCoordinator(parameters: .init(roomProxy: RoomProxyMock(.init(members: .allMembersAsAdmin)),
let coordinator = RoomRolesAndPermissionsFlowCoordinator(parameters: .init(roomProxy: JoinedRoomProxyMock(.init(members: .allMembersAsAdmin)),
mediaProvider: MockMediaProvider(),
navigationStackCoordinator: navigationStackCoordinator,
userIndicatorController: ServiceLocator.shared.userIndicatorController,
@@ -627,9 +627,9 @@ class MockScreen: Identifiable {
let clientProxy = ClientProxyMock(.init(userID: "@mock:client.com", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))))
let roomProxy = RoomProxyMock(.init(id: "whatever", name: "okay", shouldUseAutoUpdatingTimeline: true))
let roomProxy = JoinedRoomProxyMock(.init(id: "whatever", name: "okay", shouldUseAutoUpdatingTimeline: true))
clientProxy.roomForIdentifierReturnValue = roomProxy
clientProxy.roomForIdentifierReturnValue = .joined(roomProxy)
ServiceLocator.shared.settings.migratedAccounts[clientProxy.userID] = true