Use the SDK's SpaceService, SpaceRoom and SpaceRoomList. (#4455)

This commit is contained in:
Doug
2025-09-01 15:22:37 +01:00
committed by GitHub
parent 28094cfcac
commit 049bb7b740
20 changed files with 904 additions and 45 deletions
+13 -1
View File
@@ -90,6 +90,7 @@
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */; };
0D4EB2ABAA5FE8CB10FDBCB8 /* TimelineItemFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA3AF94A06D319BB37E52DA /* TimelineItemFactoryTests.swift */; };
0D617A152D099D94271D3BA8 /* SecurityAndPrivacyScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D046ABB22E680F7C5054441B /* SecurityAndPrivacyScreenViewModelProtocol.swift */; };
0DAB08C117E0391F3ADB2031 /* SpaceRoomListProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B564CA6570E1487A7C7CC /* SpaceRoomListProxy.swift */; };
0DC815CA24E1BD7F408F37D3 /* CollapsibleTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */; };
0DFCEAB8C82B151718F71D49 /* FrequentlyUsedEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2074C0449B83D5858BD2D7 /* FrequentlyUsedEmoji.swift */; };
0E08BB72B2258652CF501A8B /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = 2B9ACE4FCACB5A8812154424 /* Version */; };
@@ -208,6 +209,7 @@
24B7CD41342C143117ADA768 /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B1CC9AA154F4D5435BF60A /* Comparable.swift */; };
24BDDD09A90B8BFE3793F3AA /* ClientProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6033779EB37259F27F938937 /* ClientProxyProtocol.swift */; };
24C32D7EF94ECF9081638DF6 /* RemotePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69A05E85E4872C3221C5C287 /* RemotePreference.swift */; };
24D4E0BBC2ECD2AAD84E7159 /* SpaceRoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355C8C46DA9C0B45F1B7FC4F /* SpaceRoomProxy.swift */; };
250D2E8309C8CC48796D41D1 /* SpaceScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C11397904D19CFF0E3689F0E /* SpaceScreenModels.swift */; };
25618589E0DE0F1E95FC7B5C /* EmojiProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099F2D36C141D845A445B1E6 /* EmojiProviderTests.swift */; };
256D76972BA3254F7CB7F88B /* LocationAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */; };
@@ -820,6 +822,7 @@
9462C62798F47E39DCC182D2 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA89A2DD51B6BBE1DA55E263 /* Application.swift */; };
94871CA883F44022086FE750 /* AuthenticationStartLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98784280D98C852727BE0111 /* AuthenticationStartLogo.swift */; };
94A65DD8A353DF112EBEF67A /* SessionVerificationControllerProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D56469A9EE0CFA2B7BA9760 /* SessionVerificationControllerProxyProtocol.swift */; };
94C2B531B96493B68B976E5F /* SpaceServiceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 226A56746AD99ABDA97189E1 /* SpaceServiceProxy.swift */; };
94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; };
94E15D018D70563FA4AB4E5A /* ComposerToolbarModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D3A7375AB22721C436EB056 /* ComposerToolbarModels.swift */; };
94EB81606839C175CA6C2ADB /* RoomScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D97A4E73EA97CA08D2BB9806 /* RoomScreenTests.swift */; };
@@ -1655,6 +1658,7 @@
21BA866267F84BF4350B0CB7 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pt-BR"; path = "pt-BR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
21DD8599815136EFF5B73F38 /* UserFlowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserFlowTests.swift; sourceTree = "<group>"; };
2214C32EA81FA9168D923D4C /* CreateRoomScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomScreenTests.swift; sourceTree = "<group>"; };
226A56746AD99ABDA97189E1 /* SpaceServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceServiceProxy.swift; sourceTree = "<group>"; };
22730A30C50AC2E3D5BA8642 /* InviteUsersScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenViewModelProtocol.swift; sourceTree = "<group>"; };
227AC5D71A4CE43512062243 /* URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URL.swift; sourceTree = "<group>"; };
22DB19219E6CC4D002E15D48 /* GlobalSearchScreenCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchScreenCell.swift; sourceTree = "<group>"; };
@@ -1759,6 +1763,7 @@
34ED3AB7E0287552A5648AB3 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/InfoPlist.strings; sourceTree = "<group>"; };
353024006CB726E9F9187B3A /* AnalyticsConsentState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsConsentState.swift; sourceTree = "<group>"; };
3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = "<group>"; };
355C8C46DA9C0B45F1B7FC4F /* SpaceRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceRoomProxy.swift; sourceTree = "<group>"; };
35A057BA9BE0F079784CD061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
@@ -1873,6 +1878,7 @@
4A2B5274C1D3D2999D643786 /* EncryptionResetPasswordScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreenViewModelProtocol.swift; sourceTree = "<group>"; };
4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockTimerTests.swift; sourceTree = "<group>"; };
4AB29A2D95D3469B5F016655 /* SecureBackupControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerMock.swift; sourceTree = "<group>"; };
4B2B564CA6570E1487A7C7CC /* SpaceRoomListProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceRoomListProxy.swift; sourceTree = "<group>"; };
4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = "<group>"; };
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
@@ -5443,8 +5449,11 @@
AAAB1791344F28CDC62E764D /* Spaces */ = {
isa = PBXGroup;
children = (
4B2B564CA6570E1487A7C7CC /* SpaceRoomListProxy.swift */,
EACD4855BDAD0799FD86B7B5 /* SpaceRoomListProxyProtocol.swift */,
355C8C46DA9C0B45F1B7FC4F /* SpaceRoomProxy.swift */,
A01F2E9FD8FF95AB89A345E6 /* SpaceRoomProxyProtocol.swift */,
226A56746AD99ABDA97189E1 /* SpaceServiceProxy.swift */,
C57DB49B8426AA721BF85D83 /* SpaceServiceProxyProtocol.swift */,
);
path = Spaces;
@@ -8153,8 +8162,10 @@
F396470968764E2C3EDA92DA /* SpaceListScreenViewModel.swift in Sources */,
368EC173453FB805C677BFEF /* SpaceListScreenViewModelProtocol.swift in Sources */,
9B84F55288AB98783C11CC49 /* SpaceRoomCell.swift in Sources */,
0DAB08C117E0391F3ADB2031 /* SpaceRoomListProxy.swift in Sources */,
9FBF0078657CA4F2A9747E98 /* SpaceRoomListProxyMock.swift in Sources */,
2EAA1B35D9CA24F090F48792 /* SpaceRoomListProxyProtocol.swift in Sources */,
24D4E0BBC2ECD2AAD84E7159 /* SpaceRoomProxy.swift in Sources */,
C73CF79A578133D3AB7FB83D /* SpaceRoomProxyMock.swift in Sources */,
BE8075CA131C5EA3665C9E0D /* SpaceRoomProxyProtocol.swift in Sources */,
6CAADDC6318E41C7D7AA9526 /* SpaceScreen.swift in Sources */,
@@ -8162,6 +8173,7 @@
250D2E8309C8CC48796D41D1 /* SpaceScreenModels.swift in Sources */,
5A58C7C1837D3E5F2C3E8C8C /* SpaceScreenViewModel.swift in Sources */,
639A0A27383EC655B0E81E95 /* SpaceScreenViewModelProtocol.swift in Sources */,
94C2B531B96493B68B976E5F /* SpaceServiceProxy.swift in Sources */,
A2091F4B1332D9BF273B09D5 /* SpaceServiceProxyMock.swift in Sources */,
DB5200B87C4CE9DF0024AC4E /* SpaceServiceProxyProtocol.swift in Sources */,
DF004A5B2EABBD0574D06A04 /* SplashScreenCoordinator.swift in Sources */,
@@ -9258,7 +9270,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = 25.08.26;
version = 25.09.01;
};
};
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
@@ -158,8 +158,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : {
"revision" : "c87560bd157c83d63c3414f6c1fe1dc3a3b7d515",
"version" : "25.8.26"
"revision" : "37730751af3a42569677b04d3458629a4b8dc347",
"version" : "25.9.1"
}
},
{
@@ -91,7 +91,7 @@ class SpaceExplorerFlowCoordinator: FlowCoordinatorProtocol {
stateMachine.addRouteMapping { event, fromState, userInfo in
guard event == .selectSpace, case .spaceList = fromState else { return nil }
guard let spaceRoomListProxy = userInfo as? SpaceRoomListProxyProtocol else { fatalError("A space proxy must be provided.") }
return .spaceList(selectedSpaceID: spaceRoomListProxy.spaceRoom.id)
return .spaceList(selectedSpaceID: spaceRoomListProxy.spaceRoomProxy.id)
} handler: { [weak self] context in
guard let self, let spaceRoomListProxy = context.userInfo as? SpaceRoomListProxyProtocol else { return }
startSpaceFlow(spaceRoomListProxy: spaceRoomListProxy)
@@ -156,6 +156,6 @@ class SpaceExplorerFlowCoordinator: FlowCoordinatorProtocol {
}
coordinator.start()
selectedSpaceSubject.send(spaceRoomListProxy.spaceRoom.id)
selectedSpaceSubject.send(spaceRoomListProxy.spaceRoomProxy.id)
}
}
@@ -104,7 +104,7 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
stateMachine.addRouteMapping { event, fromState, userInfo in
guard event == .startChildFlow, case .space = fromState else { return nil }
guard let spaceRoomListProxy = userInfo as? SpaceRoomListProxyProtocol else { fatalError("A space proxy must be provided.") }
return .presentingChild(childSpaceID: spaceRoomListProxy.spaceRoom.id, previousState: fromState)
return .presentingChild(childSpaceID: spaceRoomListProxy.spaceRoomProxy.id, previousState: fromState)
} handler: { [weak self] context in
guard let self, let spaceRoomListProxy = context.userInfo as? SpaceRoomListProxyProtocol else { return }
startChildFlow(for: spaceRoomListProxy)
@@ -15840,21 +15840,21 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy
}
}
class SpaceRoomListProxyMock: SpaceRoomListProxyProtocol, @unchecked Sendable {
var spaceRoom: SpaceRoomProxyProtocol {
get { return underlyingSpaceRoom }
set(value) { underlyingSpaceRoom = value }
var spaceRoomProxy: SpaceRoomProxyProtocol {
get { return underlyingSpaceRoomProxy }
set(value) { underlyingSpaceRoomProxy = value }
}
var underlyingSpaceRoom: SpaceRoomProxyProtocol!
var underlyingSpaceRoomProxy: SpaceRoomProxyProtocol!
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceRoomProxyProtocol], Never> {
get { return underlyingSpaceRoomsPublisher }
set(value) { underlyingSpaceRoomsPublisher = value }
}
var underlyingSpaceRoomsPublisher: CurrentValuePublisher<[SpaceRoomProxyProtocol], Never>!
var paginationStatePublisher: CurrentValuePublisher<SpaceRoomListProxyPaginationState, Never> {
var paginationStatePublisher: CurrentValuePublisher<SpaceRoomListPaginationState, Never> {
get { return underlyingPaginationStatePublisher }
set(value) { underlyingPaginationStatePublisher = value }
}
var underlyingPaginationStatePublisher: CurrentValuePublisher<SpaceRoomListProxyPaginationState, Never>!
var underlyingPaginationStatePublisher: CurrentValuePublisher<SpaceRoomListPaginationState, Never>!
//MARK: - paginate
@@ -15964,7 +15964,7 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
var spaceRoomListForCalled: Bool {
return spaceRoomListForCallsCount > 0
}
var spaceRoomListForReceivedSpaceRoom: SpaceRoomProxyProtocol?
var spaceRoomListForReceivedSpaceRoomProxy: SpaceRoomProxyProtocol?
var spaceRoomListForReceivedInvocations: [SpaceRoomProxyProtocol] = []
var spaceRoomListForUnderlyingReturnValue: Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError>!
@@ -15993,14 +15993,14 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
var spaceRoomListForClosure: ((SpaceRoomProxyProtocol) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError>)?
func spaceRoomList(for spaceRoom: SpaceRoomProxyProtocol) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError> {
func spaceRoomList(for spaceRoomProxy: SpaceRoomProxyProtocol) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError> {
spaceRoomListForCallsCount += 1
spaceRoomListForReceivedSpaceRoom = spaceRoom
spaceRoomListForReceivedSpaceRoomProxy = spaceRoomProxy
DispatchQueue.main.async {
self.spaceRoomListForReceivedInvocations.append(spaceRoom)
self.spaceRoomListForReceivedInvocations.append(spaceRoomProxy)
}
if let spaceRoomListForClosure = spaceRoomListForClosure {
return await spaceRoomListForClosure(spaceRoom)
return await spaceRoomListForClosure(spaceRoomProxy)
} else {
return spaceRoomListForReturnValue
}
@@ -4572,6 +4572,71 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable {
}
}
//MARK: - spaceService
var spaceServiceUnderlyingCallsCount = 0
open var spaceServiceCallsCount: Int {
get {
if Thread.isMainThread {
return spaceServiceUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = spaceServiceUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
spaceServiceUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
spaceServiceUnderlyingCallsCount = newValue
}
}
}
}
open var spaceServiceCalled: Bool {
return spaceServiceCallsCount > 0
}
var spaceServiceUnderlyingReturnValue: SpaceService!
open var spaceServiceReturnValue: SpaceService! {
get {
if Thread.isMainThread {
return spaceServiceUnderlyingReturnValue
} else {
var returnValue: SpaceService? = nil
DispatchQueue.main.sync {
returnValue = spaceServiceUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
spaceServiceUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
spaceServiceUnderlyingReturnValue = newValue
}
}
}
}
open var spaceServiceClosure: (() -> SpaceService)?
open override func spaceService() -> SpaceService {
spaceServiceCallsCount += 1
if let spaceServiceClosure = spaceServiceClosure {
return spaceServiceClosure()
} else {
return spaceServiceReturnValue
}
}
//MARK: - startSsoLogin
open var startSsoLoginRedirectUrlIdpIdThrowableError: Error?
@@ -21111,6 +21176,551 @@ open class SessionVerificationEmojiSDKMock: MatrixRustSDK.SessionVerificationEmo
}
}
}
open class SpaceRoomListSDKMock: MatrixRustSDK.SpaceRoomList, @unchecked Sendable {
init() {
super.init(noPointer: .init())
}
public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
fatalError("init(unsafeFromRawPointer:) has not been implemented")
}
fileprivate var pointer: UnsafeMutableRawPointer!
//MARK: - paginate
open var paginateThrowableError: Error?
var paginateUnderlyingCallsCount = 0
open var paginateCallsCount: Int {
get {
if Thread.isMainThread {
return paginateUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = paginateUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
paginateUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
paginateUnderlyingCallsCount = newValue
}
}
}
}
open var paginateCalled: Bool {
return paginateCallsCount > 0
}
open var paginateClosure: (() async throws -> Void)?
open override func paginate() async throws {
if let error = paginateThrowableError {
throw error
}
paginateCallsCount += 1
try await paginateClosure?()
}
//MARK: - paginationState
var paginationStateUnderlyingCallsCount = 0
open var paginationStateCallsCount: Int {
get {
if Thread.isMainThread {
return paginationStateUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = paginationStateUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
paginationStateUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
paginationStateUnderlyingCallsCount = newValue
}
}
}
}
open var paginationStateCalled: Bool {
return paginationStateCallsCount > 0
}
var paginationStateUnderlyingReturnValue: SpaceRoomListPaginationState!
open var paginationStateReturnValue: SpaceRoomListPaginationState! {
get {
if Thread.isMainThread {
return paginationStateUnderlyingReturnValue
} else {
var returnValue: SpaceRoomListPaginationState? = nil
DispatchQueue.main.sync {
returnValue = paginationStateUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
paginationStateUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
paginationStateUnderlyingReturnValue = newValue
}
}
}
}
open var paginationStateClosure: (() -> SpaceRoomListPaginationState)?
open override func paginationState() -> SpaceRoomListPaginationState {
paginationStateCallsCount += 1
if let paginationStateClosure = paginationStateClosure {
return paginationStateClosure()
} else {
return paginationStateReturnValue
}
}
//MARK: - rooms
var roomsUnderlyingCallsCount = 0
open var roomsCallsCount: Int {
get {
if Thread.isMainThread {
return roomsUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = roomsUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
roomsUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
roomsUnderlyingCallsCount = newValue
}
}
}
}
open var roomsCalled: Bool {
return roomsCallsCount > 0
}
var roomsUnderlyingReturnValue: [SpaceRoom]!
open var roomsReturnValue: [SpaceRoom]! {
get {
if Thread.isMainThread {
return roomsUnderlyingReturnValue
} else {
var returnValue: [SpaceRoom]? = nil
DispatchQueue.main.sync {
returnValue = roomsUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
roomsUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
roomsUnderlyingReturnValue = newValue
}
}
}
}
open var roomsClosure: (() -> [SpaceRoom])?
open override func rooms() -> [SpaceRoom] {
roomsCallsCount += 1
if let roomsClosure = roomsClosure {
return roomsClosure()
} else {
return roomsReturnValue
}
}
//MARK: - subscribeToPaginationStateUpdates
var subscribeToPaginationStateUpdatesListenerUnderlyingCallsCount = 0
open var subscribeToPaginationStateUpdatesListenerCallsCount: Int {
get {
if Thread.isMainThread {
return subscribeToPaginationStateUpdatesListenerUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = subscribeToPaginationStateUpdatesListenerUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
subscribeToPaginationStateUpdatesListenerUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
subscribeToPaginationStateUpdatesListenerUnderlyingCallsCount = newValue
}
}
}
}
open var subscribeToPaginationStateUpdatesListenerCalled: Bool {
return subscribeToPaginationStateUpdatesListenerCallsCount > 0
}
open var subscribeToPaginationStateUpdatesListenerReceivedListener: SpaceRoomListPaginationStateListener?
open var subscribeToPaginationStateUpdatesListenerReceivedInvocations: [SpaceRoomListPaginationStateListener] = []
var subscribeToPaginationStateUpdatesListenerUnderlyingReturnValue: TaskHandle!
open var subscribeToPaginationStateUpdatesListenerReturnValue: TaskHandle! {
get {
if Thread.isMainThread {
return subscribeToPaginationStateUpdatesListenerUnderlyingReturnValue
} else {
var returnValue: TaskHandle? = nil
DispatchQueue.main.sync {
returnValue = subscribeToPaginationStateUpdatesListenerUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
subscribeToPaginationStateUpdatesListenerUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
subscribeToPaginationStateUpdatesListenerUnderlyingReturnValue = newValue
}
}
}
}
open var subscribeToPaginationStateUpdatesListenerClosure: ((SpaceRoomListPaginationStateListener) -> TaskHandle)?
open override func subscribeToPaginationStateUpdates(listener: SpaceRoomListPaginationStateListener) -> TaskHandle {
subscribeToPaginationStateUpdatesListenerCallsCount += 1
subscribeToPaginationStateUpdatesListenerReceivedListener = listener
DispatchQueue.main.async {
self.subscribeToPaginationStateUpdatesListenerReceivedInvocations.append(listener)
}
if let subscribeToPaginationStateUpdatesListenerClosure = subscribeToPaginationStateUpdatesListenerClosure {
return subscribeToPaginationStateUpdatesListenerClosure(listener)
} else {
return subscribeToPaginationStateUpdatesListenerReturnValue
}
}
//MARK: - subscribeToRoomUpdate
var subscribeToRoomUpdateListenerUnderlyingCallsCount = 0
open var subscribeToRoomUpdateListenerCallsCount: Int {
get {
if Thread.isMainThread {
return subscribeToRoomUpdateListenerUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = subscribeToRoomUpdateListenerUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
subscribeToRoomUpdateListenerUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
subscribeToRoomUpdateListenerUnderlyingCallsCount = newValue
}
}
}
}
open var subscribeToRoomUpdateListenerCalled: Bool {
return subscribeToRoomUpdateListenerCallsCount > 0
}
open var subscribeToRoomUpdateListenerReceivedListener: SpaceRoomListEntriesListener?
open var subscribeToRoomUpdateListenerReceivedInvocations: [SpaceRoomListEntriesListener] = []
var subscribeToRoomUpdateListenerUnderlyingReturnValue: TaskHandle!
open var subscribeToRoomUpdateListenerReturnValue: TaskHandle! {
get {
if Thread.isMainThread {
return subscribeToRoomUpdateListenerUnderlyingReturnValue
} else {
var returnValue: TaskHandle? = nil
DispatchQueue.main.sync {
returnValue = subscribeToRoomUpdateListenerUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
subscribeToRoomUpdateListenerUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
subscribeToRoomUpdateListenerUnderlyingReturnValue = newValue
}
}
}
}
open var subscribeToRoomUpdateListenerClosure: ((SpaceRoomListEntriesListener) -> TaskHandle)?
open override func subscribeToRoomUpdate(listener: SpaceRoomListEntriesListener) -> TaskHandle {
subscribeToRoomUpdateListenerCallsCount += 1
subscribeToRoomUpdateListenerReceivedListener = listener
DispatchQueue.main.async {
self.subscribeToRoomUpdateListenerReceivedInvocations.append(listener)
}
if let subscribeToRoomUpdateListenerClosure = subscribeToRoomUpdateListenerClosure {
return subscribeToRoomUpdateListenerClosure(listener)
} else {
return subscribeToRoomUpdateListenerReturnValue
}
}
}
open class SpaceServiceSDKMock: MatrixRustSDK.SpaceService, @unchecked Sendable {
init() {
super.init(noPointer: .init())
}
public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
fatalError("init(unsafeFromRawPointer:) has not been implemented")
}
fileprivate var pointer: UnsafeMutableRawPointer!
//MARK: - joinedSpaces
var joinedSpacesUnderlyingCallsCount = 0
open var joinedSpacesCallsCount: Int {
get {
if Thread.isMainThread {
return joinedSpacesUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = joinedSpacesUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
joinedSpacesUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
joinedSpacesUnderlyingCallsCount = newValue
}
}
}
}
open var joinedSpacesCalled: Bool {
return joinedSpacesCallsCount > 0
}
var joinedSpacesUnderlyingReturnValue: [SpaceRoom]!
open var joinedSpacesReturnValue: [SpaceRoom]! {
get {
if Thread.isMainThread {
return joinedSpacesUnderlyingReturnValue
} else {
var returnValue: [SpaceRoom]? = nil
DispatchQueue.main.sync {
returnValue = joinedSpacesUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
joinedSpacesUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
joinedSpacesUnderlyingReturnValue = newValue
}
}
}
}
open var joinedSpacesClosure: (() async -> [SpaceRoom])?
open override func joinedSpaces() async -> [SpaceRoom] {
joinedSpacesCallsCount += 1
if let joinedSpacesClosure = joinedSpacesClosure {
return await joinedSpacesClosure()
} else {
return joinedSpacesReturnValue
}
}
//MARK: - spaceRoomList
open var spaceRoomListSpaceIdThrowableError: Error?
var spaceRoomListSpaceIdUnderlyingCallsCount = 0
open var spaceRoomListSpaceIdCallsCount: Int {
get {
if Thread.isMainThread {
return spaceRoomListSpaceIdUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = spaceRoomListSpaceIdUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
spaceRoomListSpaceIdUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
spaceRoomListSpaceIdUnderlyingCallsCount = newValue
}
}
}
}
open var spaceRoomListSpaceIdCalled: Bool {
return spaceRoomListSpaceIdCallsCount > 0
}
open var spaceRoomListSpaceIdReceivedSpaceId: String?
open var spaceRoomListSpaceIdReceivedInvocations: [String] = []
var spaceRoomListSpaceIdUnderlyingReturnValue: SpaceRoomList!
open var spaceRoomListSpaceIdReturnValue: SpaceRoomList! {
get {
if Thread.isMainThread {
return spaceRoomListSpaceIdUnderlyingReturnValue
} else {
var returnValue: SpaceRoomList? = nil
DispatchQueue.main.sync {
returnValue = spaceRoomListSpaceIdUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
spaceRoomListSpaceIdUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
spaceRoomListSpaceIdUnderlyingReturnValue = newValue
}
}
}
}
open var spaceRoomListSpaceIdClosure: ((String) async throws -> SpaceRoomList)?
open override func spaceRoomList(spaceId: String) async throws -> SpaceRoomList {
if let error = spaceRoomListSpaceIdThrowableError {
throw error
}
spaceRoomListSpaceIdCallsCount += 1
spaceRoomListSpaceIdReceivedSpaceId = spaceId
DispatchQueue.main.async {
self.spaceRoomListSpaceIdReceivedInvocations.append(spaceId)
}
if let spaceRoomListSpaceIdClosure = spaceRoomListSpaceIdClosure {
return try await spaceRoomListSpaceIdClosure(spaceId)
} else {
return spaceRoomListSpaceIdReturnValue
}
}
//MARK: - subscribeToJoinedSpaces
var subscribeToJoinedSpacesListenerUnderlyingCallsCount = 0
open var subscribeToJoinedSpacesListenerCallsCount: Int {
get {
if Thread.isMainThread {
return subscribeToJoinedSpacesListenerUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = subscribeToJoinedSpacesListenerUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
subscribeToJoinedSpacesListenerUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
subscribeToJoinedSpacesListenerUnderlyingCallsCount = newValue
}
}
}
}
open var subscribeToJoinedSpacesListenerCalled: Bool {
return subscribeToJoinedSpacesListenerCallsCount > 0
}
open var subscribeToJoinedSpacesListenerReceivedListener: SpaceServiceJoinedSpacesListener?
open var subscribeToJoinedSpacesListenerReceivedInvocations: [SpaceServiceJoinedSpacesListener] = []
var subscribeToJoinedSpacesListenerUnderlyingReturnValue: TaskHandle!
open var subscribeToJoinedSpacesListenerReturnValue: TaskHandle! {
get {
if Thread.isMainThread {
return subscribeToJoinedSpacesListenerUnderlyingReturnValue
} else {
var returnValue: TaskHandle? = nil
DispatchQueue.main.sync {
returnValue = subscribeToJoinedSpacesListenerUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
subscribeToJoinedSpacesListenerUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
subscribeToJoinedSpacesListenerUnderlyingReturnValue = newValue
}
}
}
}
open var subscribeToJoinedSpacesListenerClosure: ((SpaceServiceJoinedSpacesListener) async -> TaskHandle)?
open override func subscribeToJoinedSpaces(listener: SpaceServiceJoinedSpacesListener) async -> TaskHandle {
subscribeToJoinedSpacesListenerCallsCount += 1
subscribeToJoinedSpacesListenerReceivedListener = listener
DispatchQueue.main.async {
self.subscribeToJoinedSpacesListenerReceivedInvocations.append(listener)
}
if let subscribeToJoinedSpacesListenerClosure = subscribeToJoinedSpacesListenerClosure {
return await subscribeToJoinedSpacesListenerClosure(listener)
} else {
return subscribeToJoinedSpacesListenerReturnValue
}
}
}
open class SpanSDKMock: MatrixRustSDK.Span, @unchecked Sendable {
init() {
super.init(noPointer: .init())
@@ -21395,6 +22005,42 @@ open class SyncServiceSDKMock: MatrixRustSDK.SyncService, @unchecked Sendable {
fileprivate var pointer: UnsafeMutableRawPointer!
//MARK: - expireSessions
var expireSessionsUnderlyingCallsCount = 0
open var expireSessionsCallsCount: Int {
get {
if Thread.isMainThread {
return expireSessionsUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = expireSessionsUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
expireSessionsUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
expireSessionsUnderlyingCallsCount = newValue
}
}
}
}
open var expireSessionsCalled: Bool {
return expireSessionsCallsCount > 0
}
open var expireSessionsClosure: (() async -> Void)?
open override func expireSessions() async {
expireSessionsCallsCount += 1
await expireSessionsClosure?()
}
//MARK: - roomListService
var roomListServiceUnderlyingCallsCount = 0
@@ -13,12 +13,12 @@ extension SpaceRoomListProxyMock {
class Configuration {
var spaceRoomProxy: SpaceRoomProxyProtocol
var initialSpaceRooms: [SpaceRoomProxyProtocol]
var paginationStateSubject: CurrentValueSubject<SpaceRoomListProxyPaginationState, Never>
var paginationStateSubject: CurrentValueSubject<SpaceRoomListPaginationState, Never>
var paginationResponses: [[SpaceRoomProxyProtocol]]
init(spaceRoomProxy: SpaceRoomProxyProtocol,
initialSpaceRooms: [SpaceRoomProxyProtocol] = [],
paginationStateSubject: CurrentValueSubject<SpaceRoomListProxyPaginationState, Never> = .init(.idle(endReached: true)),
paginationStateSubject: CurrentValueSubject<SpaceRoomListPaginationState, Never> = .init(.idle(endReached: true)),
paginationResponses: [[SpaceRoomProxyProtocol]] = []) {
self.spaceRoomProxy = spaceRoomProxy
self.initialSpaceRooms = initialSpaceRooms
@@ -32,7 +32,7 @@ extension SpaceRoomListProxyMock {
let spaceRoomsSubject: CurrentValueSubject<[SpaceRoomProxyProtocol], Never> = .init(configuration.initialSpaceRooms)
spaceRoom = configuration.spaceRoomProxy
spaceRoomProxy = configuration.spaceRoomProxy
spaceRoomsPublisher = spaceRoomsSubject.asCurrentValuePublisher()
paginationStatePublisher = configuration.paginationStateSubject.asCurrentValuePublisher()
+14
View File
@@ -78,6 +78,20 @@ extension SDKListener: RoomListLoadingStateListener where T == RoomListLoadingSt
func onUpdate(state: RoomListLoadingState) { onUpdateClosure(state) }
}
// MARK: Spaces
extension SDKListener: SpaceServiceJoinedSpacesListener where T == [SpaceListUpdate] {
func onUpdate(rooms: [SpaceListUpdate]) { onUpdateClosure(rooms) }
}
extension SDKListener: SpaceRoomListEntriesListener where T == [SpaceListUpdate] {
func onUpdate(roomUpdates: [SpaceListUpdate]) { onUpdateClosure(roomUpdates) }
}
extension SDKListener: SpaceRoomListPaginationStateListener where T == SpaceRoomListPaginationState {
func onUpdate(paginationState: SpaceRoomListPaginationState) { onUpdateClosure(paginationState) }
}
// MARK: Room
extension SDKListener: RoomInfoListener where T == RoomInfo {
@@ -35,7 +35,7 @@ final class SpaceScreenCoordinator: CoordinatorProtocol {
init(parameters: SpaceScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = SpaceScreenViewModel(spaceRoomList: parameters.spaceRoomListProxy,
viewModel = SpaceScreenViewModel(spaceRoomListProxy: parameters.spaceRoomListProxy,
spaceServiceProxy: parameters.spaceServiceProxy,
mediaProvider: parameters.mediaProvider,
userIndicatorController: parameters.userIndicatorController)
@@ -19,30 +19,32 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
actionsSubject.eraseToAnyPublisher()
}
init(spaceRoomList: SpaceRoomListProxyProtocol,
init(spaceRoomListProxy: SpaceRoomListProxyProtocol,
spaceServiceProxy: SpaceServiceProxyProtocol,
mediaProvider: MediaProviderProtocol,
userIndicatorController: UserIndicatorControllerProtocol) {
self.spaceServiceProxy = spaceServiceProxy
self.userIndicatorController = userIndicatorController
super.init(initialViewState: SpaceScreenViewState(space: spaceRoomList.spaceRoom,
rooms: spaceRoomList.spaceRoomsPublisher.value),
super.init(initialViewState: SpaceScreenViewState(space: spaceRoomListProxy.spaceRoomProxy,
rooms: spaceRoomListProxy.spaceRoomsPublisher.value),
mediaProvider: mediaProvider)
spaceRoomList.spaceRoomsPublisher
spaceRoomListProxy.spaceRoomsPublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.rooms, on: self)
.store(in: &cancellables)
spaceRoomList.paginationStatePublisher
// As the server is slow, we just let the screen automatically paginate everything in. We can
// switch this to use the scroll position once Synapse receives some performance improvements.
spaceRoomListProxy.paginationStatePublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] paginationState in
switch paginationState {
case .idle(let endReached):
self?.state.isPaginating = false
guard !endReached else { return }
Task { await spaceRoomList.paginate() }
Task { await spaceRoomListProxy.paginate() }
case .loading:
self?.state.isPaginating = true
}
@@ -64,7 +64,7 @@ struct SpaceScreen_Previews: PreviewProvider, TestablePreview {
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceRoomProxy: spaceRoomProxy,
initialSpaceRooms: .mockSpaceList))
let viewModel = SpaceScreenViewModel(spaceRoomList: spaceRoomListProxy,
let viewModel = SpaceScreenViewModel(spaceRoomListProxy: spaceRoomListProxy,
spaceServiceProxy: SpaceServiceProxyMock(.init()),
mediaProvider: MediaProviderMock(configuration: .init()),
userIndicatorController: UserIndicatorControllerMock())
@@ -166,9 +166,7 @@ class ClientProxy: ClientProxyProtocol {
secureBackupController = SecureBackupController(encryption: client.encryption())
// Temporarily using the mock until the SDK is updated.
// spaceService = SpaceServiceProxy(spaceService: client.spaceService())
spaceService = SpaceServiceProxyMock(.init())
spaceService = SpaceServiceProxy(spaceService: client.spaceService())
let configuredAppService = try await ClientProxyServices(client: client,
actionsSubject: actionsSubject,
@@ -0,0 +1,82 @@
//
// Copyright 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 MatrixRustSDK
class SpaceRoomListProxy: SpaceRoomListProxyProtocol {
private let spaceRoomList: SpaceRoomListProtocol
let spaceRoomProxy: SpaceRoomProxyProtocol
private var spaceRoomsHandle: TaskHandle?
private let spaceRoomsSubject = CurrentValueSubject<[SpaceRoomProxyProtocol], Never>([])
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceRoomProxyProtocol], Never> {
spaceRoomsSubject.asCurrentValuePublisher()
}
private let paginationStateHandle: TaskHandle
let paginationStatePublisher: CurrentValuePublisher<SpaceRoomListPaginationState, Never>
init(_ spaceRoomList: SpaceRoomListProtocol, spaceRoomProxy: SpaceRoomProxyProtocol) {
self.spaceRoomList = spaceRoomList
self.spaceRoomProxy = spaceRoomProxy
let paginationStateSubject = CurrentValueSubject<SpaceRoomListPaginationState, Never>(spaceRoomList.paginationState())
paginationStatePublisher = paginationStateSubject.asCurrentValuePublisher()
paginationStateHandle = spaceRoomList.subscribeToPaginationStateUpdates(listener: SDKListener { paginationState in
paginationStateSubject.send(paginationState)
})
spaceRoomsHandle = spaceRoomList.subscribeToRoomUpdate(listener: SDKListener { [weak self] updates in
self?.handleUpdates(updates)
})
}
func paginate() async {
do {
try await spaceRoomList.paginate()
} catch {
MXLog.error("Pagination failure: \(error)")
}
}
// MARK: - Private
private func handleUpdates(_ updates: [SpaceListUpdate]) {
var rooms = spaceRoomsSubject.value
for update in updates {
switch update {
case .append(let spaceRooms):
rooms.append(contentsOf: spaceRooms.map(SpaceRoomProxy.init))
case .clear:
rooms.removeAll()
case .pushFront(let spaceRoom):
rooms.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: 0)
case .pushBack(let spaceRoom):
rooms.append(SpaceRoomProxy(spaceRoom: spaceRoom))
case .popFront:
rooms.removeFirst()
case .popBack:
rooms.removeLast()
case .insert(let index, let spaceRoom):
rooms.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: Int(index))
case .set(let index, let spaceRoom):
rooms[Int(index)] = SpaceRoomProxy(spaceRoom: spaceRoom)
case .remove(let index):
rooms.remove(at: Int(index))
case .truncate(let length):
rooms.removeSubrange(Int(length)..<rooms.count)
case .reset(let spaceRooms):
rooms = spaceRooms.map(SpaceRoomProxy.init)
}
}
spaceRoomsSubject.send(rooms)
}
}
@@ -8,18 +8,12 @@
import Combine
import MatrixRustSDK
// Temporary until the SDK is updated.
enum SpaceRoomListProxyPaginationState: Equatable {
case idle(endReached: Bool)
case loading
}
// sourcery: AutoMockable
protocol SpaceRoomListProxyProtocol {
var spaceRoom: SpaceRoomProxyProtocol { get }
var spaceRoomProxy: SpaceRoomProxyProtocol { get }
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceRoomProxyProtocol], Never> { get }
var paginationStatePublisher: CurrentValuePublisher<SpaceRoomListProxyPaginationState, Never> { get }
var paginationStatePublisher: CurrentValuePublisher<SpaceRoomListPaginationState, Never> { get }
func paginate() async
}
@@ -0,0 +1,34 @@
//
// Copyright 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 Foundation
import MatrixRustSDK
class SpaceRoomProxy: SpaceRoomProxyProtocol {
private let spaceRoom: SpaceRoom
init(spaceRoom: SpaceRoom) {
self.spaceRoom = spaceRoom
}
lazy var id = spaceRoom.roomId
var name: String? { spaceRoom.name }
var avatarURL: URL? { spaceRoom.avatarUrl.flatMap(URL.init) }
var isSpace: Bool { spaceRoom.roomType == .space }
var childrenCount: Int { Int(spaceRoom.childrenCount) }
var joinedMembersCount: Int { Int(spaceRoom.numJoinedMembers) }
var heroes: [UserProfileProxy] { (spaceRoom.heroes ?? []).map(UserProfileProxy.init) }
var topic: String? { spaceRoom.topic }
var canonicalAlias: String? { spaceRoom.canonicalAlias }
var joinRule: JoinRule? { spaceRoom.joinRule }
var worldReadable: Bool? { spaceRoom.worldReadable }
var guestCanJoin: Bool { spaceRoom.guestCanJoin }
var state: Membership? { spaceRoom.state }
}
@@ -0,0 +1,76 @@
//
// Copyright 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
class SpaceServiceProxy: SpaceServiceProxyProtocol {
private let spaceService: SpaceServiceProtocol
private var joinedSpacesHandle: TaskHandle?
private let spacesSubject = CurrentValueSubject<[SpaceRoomProxyProtocol], Never>([])
var joinedSpacesPublisher: CurrentValuePublisher<[SpaceRoomProxyProtocol], Never> {
spacesSubject.asCurrentValuePublisher()
}
init(spaceService: SpaceServiceProtocol) {
self.spaceService = spaceService
Task { await setupSubscriptions() }
}
private func setupSubscriptions() async {
joinedSpacesHandle = await spaceService.subscribeToJoinedSpaces(listener: SDKListener { [weak self] updates in
self?.handleUpdates(updates)
})
}
func spaceRoomList(for spaceRoomProxy: SpaceRoomProxyProtocol) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError> {
do {
return try await .success(SpaceRoomListProxy(spaceService.spaceRoomList(spaceId: spaceRoomProxy.id), spaceRoomProxy: spaceRoomProxy))
} catch {
MXLog.error("Failed creating space room list for \(spaceRoomProxy.id): \(error)")
return .failure(.sdkError(error))
}
}
// MARK: - Private
private func handleUpdates(_ updates: [SpaceListUpdate]) {
var spaces = spacesSubject.value
for update in updates {
switch update {
case .append(let spaceRooms):
spaces.append(contentsOf: spaceRooms.map(SpaceRoomProxy.init))
case .clear:
spaces.removeAll()
case .pushFront(let spaceRoom):
spaces.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: 0)
case .pushBack(let spaceRoom):
spaces.append(SpaceRoomProxy(spaceRoom: spaceRoom))
case .popFront:
spaces.removeFirst()
case .popBack:
spaces.removeLast()
case .insert(let index, let spaceRoom):
spaces.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: Int(index))
case .set(let index, let spaceRoom):
spaces[Int(index)] = SpaceRoomProxy(spaceRoom: spaceRoom)
case .remove(let index):
spaces.remove(at: Int(index))
case .truncate(let length):
spaces.removeSubrange(Int(length)..<spaces.count)
case .reset(let spaceRooms):
spaces = spaceRooms.map(SpaceRoomProxy.init)
}
}
spacesSubject.send(spaces)
}
}
@@ -15,5 +15,5 @@ enum SpaceServiceProxyError: Error {
protocol SpaceServiceProxyProtocol {
var joinedSpacesPublisher: CurrentValuePublisher<[SpaceRoomProxyProtocol], Never> { get }
func spaceRoomList(for spaceRoom: SpaceRoomProxyProtocol) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError>
func spaceRoomList(for spaceRoomProxy: SpaceRoomProxyProtocol) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError>
}
@@ -52,7 +52,7 @@ class SpaceListScreenViewModelTests: XCTestCase {
let action = try await deferred.fulfill()
switch action {
case .selectSpace(let spaceRoomListProxy) where spaceRoomListProxy.spaceRoom.id == selectedSpace.id:
case .selectSpace(let spaceRoomListProxy) where spaceRoomListProxy.spaceRoomProxy.id == selectedSpace.id:
break
default:
XCTFail("The action should select the space.")
@@ -9,12 +9,13 @@ import Combine
import XCTest
@testable import ElementX
import MatrixRustSDK
@MainActor
class SpaceScreenViewModelTests: XCTestCase {
var spaceRoomListProxy: SpaceRoomListProxyMock!
let mockSpaceRooms = [SpaceRoomProxyProtocol].mockSpaceList
var paginationStateSubject: CurrentValueSubject<SpaceRoomListProxyPaginationState, Never> = .init(.idle(endReached: true))
var paginationStateSubject: CurrentValueSubject<SpaceRoomListPaginationState, Never> = .init(.idle(endReached: true))
var viewModel: SpaceScreenViewModelProtocol!
@@ -97,7 +98,7 @@ class SpaceScreenViewModelTests: XCTestCase {
let action = try await deferred.fulfill()
switch action {
case .selectSpace(let spaceRoomListProxy) where spaceRoomListProxy.spaceRoom.id == selectedSpace.id:
case .selectSpace(let spaceRoomListProxy) where spaceRoomListProxy.spaceRoomProxy.id == selectedSpace.id:
break
default:
XCTFail("The action should select the space.")
@@ -114,7 +115,7 @@ class SpaceScreenViewModelTests: XCTestCase {
let spaceServiceProxy = SpaceServiceProxyMock(.init())
spaceServiceProxy.spaceRoomListForClosure = { .success(SpaceRoomListProxyMock(.init(spaceRoomProxy: $0))) }
viewModel = SpaceScreenViewModel(spaceRoomList: spaceRoomListProxy,
viewModel = SpaceScreenViewModel(spaceRoomListProxy: spaceRoomListProxy,
spaceServiceProxy: spaceServiceProxy,
mediaProvider: MediaProviderMock(configuration: .init()),
userIndicatorController: UserIndicatorControllerMock())
+1 -1
View File
@@ -68,7 +68,7 @@ packages:
# Element/Matrix dependencies
MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 25.08.26
exactVersion: 25.09.01
# path: ../matrix-rust-sdk
Compound:
url: https://github.com/element-hq/compound-ios