From e36dcfbc99d3b669de0863beb6d7345cf91ee719 Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:03:11 +0100 Subject: [PATCH] Add some new space properties. (#4544) * Use the via property on SpaceRoom. * Fall back to the canonical alias as a space room name if needs be. * Use SpaceRoom.isDirect for computing the name/avatar. * Pass in the parent space as a workaround for no restricted join rules. --- .../en.lproj/Localizable.strings | 1 + ElementX/Sources/Generated/Strings.swift | 4 ++ .../Mocks/Generated/GeneratedMocks.swift | 51 ++++++++++--------- .../Sources/Mocks/SpaceRoomProxyMock.swift | 6 +++ .../Sources/Mocks/SpaceServiceProxyMock.swift | 2 +- .../JoinRoomScreenViewModel.swift | 2 +- .../Spaces/Common/SpaceHeaderView.swift | 34 +++++-------- .../Screens/Spaces/Common/SpaceRoomCell.swift | 32 +++++++++--- .../SpaceListScreenViewModel.swift | 2 +- .../SpaceScreen/SpaceScreenViewModel.swift | 6 ++- .../Spaces/SpaceScreen/View/SpaceScreen.swift | 1 + .../Services/Spaces/SpaceRoomListProxy.swift | 17 ++++--- .../Services/Spaces/SpaceRoomProxy.swift | 10 +++- .../Spaces/SpaceRoomProxyProtocol.swift | 41 ++++++++++++++- .../Services/Spaces/SpaceServiceProxy.swift | 17 ++++--- .../Spaces/SpaceServiceProxyProtocol.swift | 2 +- .../spaceHeaderView.iPad-en-GB-0.png | 4 +- .../spaceHeaderView.iPad-pseudo-0.png | 4 +- .../spaceHeaderView.iPhone-16-en-GB-0.png | 4 +- .../spaceHeaderView.iPhone-16-pseudo-0.png | 4 +- .../spaceRoomCell.iPad-en-GB-0.png | 4 +- .../spaceRoomCell.iPad-pseudo-0.png | 4 +- .../spaceRoomCell.iPhone-16-en-GB-0.png | 4 +- .../spaceRoomCell.iPhone-16-pseudo-0.png | 4 +- .../PreviewTests/spaceScreen.iPad-en-GB-0.png | 4 +- .../spaceScreen.iPad-pseudo-0.png | 4 +- .../spaceScreen.iPhone-16-en-GB-0.png | 4 +- .../spaceScreen.iPhone-16-pseudo-0.png | 4 +- .../SpaceListScreenViewModelTests.swift | 2 +- .../Sources/SpaceScreenViewModelTests.swift | 2 +- 30 files changed, 178 insertions(+), 102 deletions(-) diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index fd5138c28..089950717 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -645,6 +645,7 @@ "screen_security_and_privacy_title" = "Security & privacy"; "screen_space_list_description" = "Spaces you have created or joined."; "screen_space_list_details" = "%1$@ • %2$@"; +"screen_space_list_parent_space" = "%1$@ space"; "screen_space_list_title" = "Spaces"; "screen_start_chat_join_room_by_address_action" = "Join room by address"; "screen_start_chat_join_room_by_address_invalid_address" = "Not a valid address"; diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index 4b2c3a331..e92afe471 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -2880,6 +2880,10 @@ internal enum L10n { internal static func screenSpaceListDetails(_ p1: Any, _ p2: Any) -> String { return L10n.tr("Localizable", "screen_space_list_details", String(describing: p1), String(describing: p2)) } + /// %1$@ space + internal static func screenSpaceListParentSpace(_ p1: Any) -> String { + return L10n.tr("Localizable", "screen_space_list_parent_space", String(describing: p1)) + } /// Spaces internal static var screenSpaceListTitle: String { return L10n.tr("Localizable", "screen_space_list_title") } /// An error occurred when trying to start a chat diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 645a2804f..e303ceed8 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -15938,6 +15938,8 @@ class SpaceRoomProxyMock: SpaceRoomProxyProtocol, @unchecked Sendable { set(value) { underlyingIsSpace = value } } var underlyingIsSpace: Bool! + var isDirect: Bool? + var parent: SpaceRoomProxyProtocol? var childrenCount: Int { get { return underlyingChildrenCount } set(value) { underlyingChildrenCount = value } @@ -15959,6 +15961,7 @@ class SpaceRoomProxyMock: SpaceRoomProxyProtocol, @unchecked Sendable { } var underlyingGuestCanJoin: Bool! var state: Membership? + var via: [String] = [] } class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable { @@ -15970,15 +15973,15 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable { //MARK: - spaceRoomList - var spaceRoomListSpaceIDUnderlyingCallsCount = 0 - var spaceRoomListSpaceIDCallsCount: Int { + var spaceRoomListSpaceIDParentUnderlyingCallsCount = 0 + var spaceRoomListSpaceIDParentCallsCount: Int { get { if Thread.isMainThread { - return spaceRoomListSpaceIDUnderlyingCallsCount + return spaceRoomListSpaceIDParentUnderlyingCallsCount } else { var returnValue: Int? = nil DispatchQueue.main.sync { - returnValue = spaceRoomListSpaceIDUnderlyingCallsCount + returnValue = spaceRoomListSpaceIDParentUnderlyingCallsCount } return returnValue! @@ -15986,29 +15989,29 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable { } set { if Thread.isMainThread { - spaceRoomListSpaceIDUnderlyingCallsCount = newValue + spaceRoomListSpaceIDParentUnderlyingCallsCount = newValue } else { DispatchQueue.main.sync { - spaceRoomListSpaceIDUnderlyingCallsCount = newValue + spaceRoomListSpaceIDParentUnderlyingCallsCount = newValue } } } } - var spaceRoomListSpaceIDCalled: Bool { - return spaceRoomListSpaceIDCallsCount > 0 + var spaceRoomListSpaceIDParentCalled: Bool { + return spaceRoomListSpaceIDParentCallsCount > 0 } - var spaceRoomListSpaceIDReceivedSpaceID: String? - var spaceRoomListSpaceIDReceivedInvocations: [String] = [] + var spaceRoomListSpaceIDParentReceivedArguments: (spaceID: String, parent: SpaceRoomProxyProtocol?)? + var spaceRoomListSpaceIDParentReceivedInvocations: [(spaceID: String, parent: SpaceRoomProxyProtocol?)] = [] - var spaceRoomListSpaceIDUnderlyingReturnValue: Result! - var spaceRoomListSpaceIDReturnValue: Result! { + var spaceRoomListSpaceIDParentUnderlyingReturnValue: Result! + var spaceRoomListSpaceIDParentReturnValue: Result! { get { if Thread.isMainThread { - return spaceRoomListSpaceIDUnderlyingReturnValue + return spaceRoomListSpaceIDParentUnderlyingReturnValue } else { var returnValue: Result? = nil DispatchQueue.main.sync { - returnValue = spaceRoomListSpaceIDUnderlyingReturnValue + returnValue = spaceRoomListSpaceIDParentUnderlyingReturnValue } return returnValue! @@ -16016,26 +16019,26 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable { } set { if Thread.isMainThread { - spaceRoomListSpaceIDUnderlyingReturnValue = newValue + spaceRoomListSpaceIDParentUnderlyingReturnValue = newValue } else { DispatchQueue.main.sync { - spaceRoomListSpaceIDUnderlyingReturnValue = newValue + spaceRoomListSpaceIDParentUnderlyingReturnValue = newValue } } } } - var spaceRoomListSpaceIDClosure: ((String) async -> Result)? + var spaceRoomListSpaceIDParentClosure: ((String, SpaceRoomProxyProtocol?) async -> Result)? - func spaceRoomList(spaceID: String) async -> Result { - spaceRoomListSpaceIDCallsCount += 1 - spaceRoomListSpaceIDReceivedSpaceID = spaceID + func spaceRoomList(spaceID: String, parent: SpaceRoomProxyProtocol?) async -> Result { + spaceRoomListSpaceIDParentCallsCount += 1 + spaceRoomListSpaceIDParentReceivedArguments = (spaceID: spaceID, parent: parent) DispatchQueue.main.async { - self.spaceRoomListSpaceIDReceivedInvocations.append(spaceID) + self.spaceRoomListSpaceIDParentReceivedInvocations.append((spaceID: spaceID, parent: parent)) } - if let spaceRoomListSpaceIDClosure = spaceRoomListSpaceIDClosure { - return await spaceRoomListSpaceIDClosure(spaceID) + if let spaceRoomListSpaceIDParentClosure = spaceRoomListSpaceIDParentClosure { + return await spaceRoomListSpaceIDParentClosure(spaceID, parent) } else { - return spaceRoomListSpaceIDReturnValue + return spaceRoomListSpaceIDParentReturnValue } } } diff --git a/ElementX/Sources/Mocks/SpaceRoomProxyMock.swift b/ElementX/Sources/Mocks/SpaceRoomProxyMock.swift index 7c39c9b3c..f21f4c055 100644 --- a/ElementX/Sources/Mocks/SpaceRoomProxyMock.swift +++ b/ElementX/Sources/Mocks/SpaceRoomProxyMock.swift @@ -15,6 +15,8 @@ extension SpaceRoomProxyMock { var avatarURL: URL? var isSpace: Bool + var isDirect: Bool? + var parent: SpaceRoomProxyProtocol? var childrenCount = 0 var joinedMembersCount = 0 @@ -35,6 +37,8 @@ extension SpaceRoomProxyMock { name = configuration.name avatarURL = configuration.avatarURL isSpace = configuration.isSpace + isDirect = configuration.isDirect + parent = configuration.parent childrenCount = configuration.childrenCount joinedMembersCount = configuration.joinedMembersCount heroes = configuration.heroes @@ -125,8 +129,10 @@ extension [SpaceRoomProxyProtocol] { SpaceRoomProxyMock(.init(id: "!\(typeName.lowercased())3:matrix.org", name: "Joined \(typeName)", isSpace: isSpace, + parent: SpaceRoomProxyMock(.init(name: "Company", isSpace: true)), joinedMembersCount: 123, topic: "Discussion on specific topic goes here.", + joinRule: .restricted(rules: []), state: .joined)) ] } diff --git a/ElementX/Sources/Mocks/SpaceServiceProxyMock.swift b/ElementX/Sources/Mocks/SpaceServiceProxyMock.swift index f9b3c1dc2..48c270675 100644 --- a/ElementX/Sources/Mocks/SpaceServiceProxyMock.swift +++ b/ElementX/Sources/Mocks/SpaceServiceProxyMock.swift @@ -19,7 +19,7 @@ extension SpaceServiceProxyMock { self.init() joinedSpacesPublisher = .init(configuration.joinedSpaces) - spaceRoomListSpaceIDClosure = { spaceID in + spaceRoomListSpaceIDParentClosure = { spaceID, _ in if let spaceRoomList = configuration.spaceRoomLists[spaceID] { .success(spaceRoomList) } else { diff --git a/ElementX/Sources/Screens/JoinRoomScreen/JoinRoomScreenViewModel.swift b/ElementX/Sources/Screens/JoinRoomScreen/JoinRoomScreenViewModel.swift index ad49f9ed6..639435a56 100644 --- a/ElementX/Sources/Screens/JoinRoomScreen/JoinRoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/JoinRoomScreen/JoinRoomScreenViewModel.swift @@ -286,7 +286,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo return } - switch await clientProxy.spaceService.spaceRoomList(spaceID: roomID) { + switch await clientProxy.spaceService.spaceRoomList(spaceID: roomID, parent: nil) { case .success(let spaceRoomListProxy): actionsSubject.send(.joined(.space(spaceRoomListProxy))) case .failure(let error): diff --git a/ElementX/Sources/Screens/Spaces/Common/SpaceHeaderView.swift b/ElementX/Sources/Screens/Spaces/Common/SpaceHeaderView.swift index 0a0110941..4d8aae4f9 100644 --- a/ElementX/Sources/Screens/Spaces/Common/SpaceHeaderView.swift +++ b/ElementX/Sources/Screens/Spaces/Common/SpaceHeaderView.swift @@ -14,8 +14,6 @@ struct SpaceHeaderView: View { @State private var isPresentingTopic = false - var title: String { spaceRoomProxy.name ?? "" } - var body: some View { VStack(spacing: 16) { RoomAvatarImage(avatar: spaceRoomProxy.avatar, @@ -24,7 +22,7 @@ struct SpaceHeaderView: View { .accessibilityHidden(true) VStack(spacing: 8) { - Text(title) + Text(spaceRoomProxy.computedName) .font(.compound.headingLGBold) .foregroundStyle(.compound.textPrimary) .multilineTextAlignment(.center) @@ -76,31 +74,24 @@ struct SpaceHeaderView: View { } var spaceDetailsVisibilityTitle: String { - switch spaceRoomProxy.joinRule { - case .public: - L10n.commonPublicSpace - case .restricted(let rules), .knockRestricted(let rules): - // FIXME: Get this from the rule (falling back to a passed in parent??) - " space" - case .invite, .knock, .private, .custom, .none: - L10n.commonPrivateSpace + switch spaceRoomProxy.visibility { + case .public: L10n.commonPublicSpace + case .private: L10n.commonPrivateSpace + case .restricted(let parentName): L10n.screenSpaceListParentSpace(parentName) + case .none: L10n.commonPrivateSpace } } var spaceDetailsVisibilityIcon: KeyPath { - switch spaceRoomProxy.joinRule { - case .public: - \.public - case .restricted, .knockRestricted: - \.space - case .invite, .knock, .private, .custom, .none: - \.lock + switch spaceRoomProxy.visibility { + case .public: \.public + case .private: \.lock + case .restricted: \.space + case .none: \.lock } } } -import MatrixRustSDK - struct SpaceHeaderMembersView: View { let heroes: [UserProfileProxy] let joinedCount: Int @@ -159,6 +150,8 @@ struct SpaceHeaderMembersView: View { } } +// MARK: - Previews + struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview { static let mediaProvider = MediaProviderMock(configuration: .init()) @@ -190,6 +183,7 @@ struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview { SpaceRoomProxyMock(.init(id: "!space3:matrix.org", name: "Subspace", isSpace: true, + parent: SpaceRoomProxyMock(.init(name: "Foundation", isSpace: true)), childrenCount: 30, joinedMembersCount: 123, heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose], diff --git a/ElementX/Sources/Screens/Spaces/Common/SpaceRoomCell.swift b/ElementX/Sources/Screens/Spaces/Common/SpaceRoomCell.swift index a4f78594a..24390fda1 100644 --- a/ElementX/Sources/Screens/Spaces/Common/SpaceRoomCell.swift +++ b/ElementX/Sources/Screens/Spaces/Common/SpaceRoomCell.swift @@ -25,12 +25,26 @@ struct SpaceRoomCell: View { private var subtitle: String { if spaceRoomProxy.isSpace { - spaceRoomProxy.joinRule == .public ? L10n.commonPublicSpace : L10n.commonPrivateSpace + switch spaceRoomProxy.visibility { + case .public: L10n.commonPublicSpace + case .private: L10n.commonPrivateSpace + case .restricted(let parentName): L10n.screenSpaceListParentSpace(parentName) + case .none: L10n.commonPrivateSpace + } } else { L10n.commonMemberCount(spaceRoomProxy.joinedMembersCount) } } + var visibilityIcon: KeyPath? { + switch spaceRoomProxy.visibility { + case .public: \.public + case .private: \.lockSolid + case .restricted: nil + case .none: \.lockSolid + } + } + private var details: String { if spaceRoomProxy.isSpace { L10n.screenSpaceListDetails(L10n.commonRooms(spaceRoomProxy.childrenCount), @@ -77,12 +91,12 @@ struct SpaceRoomCell: View { private var content: some View { HStack(spacing: 16) { VStack(alignment: .leading, spacing: 2) { - Text(spaceRoomProxy.name ?? spaceRoomProxy.id) + Text(spaceRoomProxy.computedName) .font(.compound.bodyLGSemibold) .foregroundColor(.compound.textPrimary) .lineLimit(1) - visibilityLabel + subtitleLabel Text(details) .font(.compound.bodyMD) @@ -95,17 +109,19 @@ struct SpaceRoomCell: View { } } - private var visibilityLabel: some View { + private var subtitleLabel: some View { Label { Text(subtitle) .font(.compound.bodyMD) .foregroundStyle(.compound.textSecondary) .lineLimit(1) } icon: { - CompoundIcon(spaceRoomProxy.joinRule == .public ? \.public : \.lockSolid, - size: .xSmall, - relativeTo: .compound.bodyMD) - .foregroundStyle(.compound.iconTertiary) + if let visibilityIcon { + CompoundIcon(visibilityIcon, + size: .xSmall, + relativeTo: .compound.bodyMD) + .foregroundStyle(.compound.iconTertiary) + } } .labelStyle(.custom(spacing: 4)) } diff --git a/ElementX/Sources/Screens/Spaces/SpaceListScreen/SpaceListScreenViewModel.swift b/ElementX/Sources/Screens/Spaces/SpaceListScreen/SpaceListScreenViewModel.swift index c06ff51c7..d711fb7b6 100644 --- a/ElementX/Sources/Screens/Spaces/SpaceListScreen/SpaceListScreenViewModel.swift +++ b/ElementX/Sources/Screens/Spaces/SpaceListScreen/SpaceListScreenViewModel.swift @@ -68,7 +68,7 @@ class SpaceListScreenViewModel: SpaceListScreenViewModelType, SpaceListScreenVie // MARK: - Private private func selectSpace(_ spaceRoomProxy: SpaceRoomProxyProtocol) async { - switch await spaceServiceProxy.spaceRoomList(spaceID: spaceRoomProxy.id) { + switch await spaceServiceProxy.spaceRoomList(spaceID: spaceRoomProxy.id, parent: nil) { case .success(let spaceRoomListProxy): actionsSubject.send(.selectSpace(spaceRoomListProxy)) case .failure(let error): diff --git a/ElementX/Sources/Screens/Spaces/SpaceScreen/SpaceScreenViewModel.swift b/ElementX/Sources/Screens/Spaces/SpaceScreen/SpaceScreenViewModel.swift index 366d21bfd..fb9c53796 100644 --- a/ElementX/Sources/Screens/Spaces/SpaceScreen/SpaceScreenViewModel.swift +++ b/ElementX/Sources/Screens/Spaces/SpaceScreen/SpaceScreenViewModel.swift @@ -11,6 +11,7 @@ import SwiftUI typealias SpaceScreenViewModelType = StateStoreViewModelV2 class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtocol { + private let spaceRoomListProxy: SpaceRoomListProxyProtocol private let spaceServiceProxy: SpaceServiceProxyProtocol private let clientProxy: ClientProxyProtocol private let userIndicatorController: UserIndicatorControllerProtocol @@ -25,6 +26,7 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc selectedSpaceRoomPublisher: CurrentValuePublisher, userSession: UserSessionProtocol, userIndicatorController: UserIndicatorControllerProtocol) { + self.spaceRoomListProxy = spaceRoomListProxy self.spaceServiceProxy = spaceServiceProxy clientProxy = userSession.clientProxy self.userIndicatorController = userIndicatorController @@ -93,7 +95,7 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc state.joiningRoomIDs.insert(spaceRoomProxy.id) defer { state.joiningRoomIDs.remove(spaceRoomProxy.id) } - guard case .success = await clientProxy.joinRoom(spaceRoomProxy.id, via: []) else { + guard case .success = await clientProxy.joinRoom(spaceRoomProxy.id, via: spaceRoomProxy.via) else { showFailureIndicator() return } @@ -109,7 +111,7 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc } private func selectSpace(_ spaceRoomProxy: SpaceRoomProxyProtocol) async { - switch await spaceServiceProxy.spaceRoomList(spaceID: spaceRoomProxy.id) { + switch await spaceServiceProxy.spaceRoomList(spaceID: spaceRoomProxy.id, parent: spaceRoomListProxy.spaceRoomProxy) { case .success(let spaceRoomListProxy): actionsSubject.send(.selectSpace(spaceRoomListProxy)) case .failure(let error): diff --git a/ElementX/Sources/Screens/Spaces/SpaceScreen/View/SpaceScreen.swift b/ElementX/Sources/Screens/Spaces/SpaceScreen/View/SpaceScreen.swift index 8707fd5e3..40b3879ff 100644 --- a/ElementX/Sources/Screens/Spaces/SpaceScreen/View/SpaceScreen.swift +++ b/ElementX/Sources/Screens/Spaces/SpaceScreen/View/SpaceScreen.swift @@ -68,6 +68,7 @@ struct SpaceScreen_Previews: PreviewProvider, TestablePreview { let spaceRoomProxy = SpaceRoomProxyMock(.init(id: "!eng-space:matrix.org", name: "Engineering Team", isSpace: true, + parent: SpaceRoomProxyMock(.init(name: "MegaGroup", isSpace: true)), childrenCount: 30, joinedMembersCount: 76, heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose], diff --git a/ElementX/Sources/Services/Spaces/SpaceRoomListProxy.swift b/ElementX/Sources/Services/Spaces/SpaceRoomListProxy.swift index f5e76d778..2803633d4 100644 --- a/ElementX/Sources/Services/Spaces/SpaceRoomListProxy.swift +++ b/ElementX/Sources/Services/Spaces/SpaceRoomListProxy.swift @@ -21,11 +21,12 @@ class SpaceRoomListProxy: SpaceRoomListProxyProtocol { private let paginationStateHandle: TaskHandle let paginationStatePublisher: CurrentValuePublisher - init(_ spaceRoomList: SpaceRoomListProtocol) throws { + // Parent is temporary until we get the restricted AllowRules from the server. + init(_ spaceRoomList: SpaceRoomListProtocol, parent: SpaceRoomProxyProtocol?) throws { guard let spaceRoom = spaceRoomList.space() else { throw SpaceRoomListProxyError.missingSpace } self.spaceRoomList = spaceRoomList - spaceRoomProxy = SpaceRoomProxy(spaceRoom: spaceRoom) + spaceRoomProxy = SpaceRoomProxy(spaceRoom: spaceRoom, parent: parent) let paginationStateSubject = CurrentValueSubject(spaceRoomList.paginationState()) paginationStatePublisher = paginationStateSubject.asCurrentValuePublisher() @@ -55,27 +56,27 @@ class SpaceRoomListProxy: SpaceRoomListProxyProtocol { for update in updates { switch update { case .append(let spaceRooms): - rooms.append(contentsOf: spaceRooms.map(SpaceRoomProxy.init)) + rooms.append(contentsOf: spaceRooms.map { SpaceRoomProxy(spaceRoom: $0, parent: spaceRoomProxy) }) case .clear: rooms.removeAll() case .pushFront(let spaceRoom): - rooms.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: 0) + rooms.insert(SpaceRoomProxy(spaceRoom: spaceRoom, parent: spaceRoomProxy), at: 0) case .pushBack(let spaceRoom): - rooms.append(SpaceRoomProxy(spaceRoom: spaceRoom)) + rooms.append(SpaceRoomProxy(spaceRoom: spaceRoom, parent: spaceRoomProxy)) case .popFront: rooms.removeFirst() case .popBack: rooms.removeLast() case .insert(let index, let spaceRoom): - rooms.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: Int(index)) + rooms.insert(SpaceRoomProxy(spaceRoom: spaceRoom, parent: spaceRoomProxy), at: Int(index)) case .set(let index, let spaceRoom): - rooms[Int(index)] = SpaceRoomProxy(spaceRoom: spaceRoom) + rooms[Int(index)] = SpaceRoomProxy(spaceRoom: spaceRoom, parent: spaceRoomProxy) case .remove(let index): rooms.remove(at: Int(index)) case .truncate(let length): rooms.removeSubrange(Int(length).. Result { + // The parent here is temporary until we get the restricted AllowRules from the server. + func spaceRoomList(spaceID: String, parent: SpaceRoomProxyProtocol?) async -> Result { do { - return try await .success(SpaceRoomListProxy(spaceService.spaceRoomList(spaceId: spaceID))) + return try await .success(SpaceRoomListProxy(spaceService.spaceRoomList(spaceId: spaceID), parent: parent)) } catch { MXLog.error("Failed creating space room list for \(spaceID): \(error)") return .failure(.sdkError(error)) @@ -47,27 +48,27 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol { for update in updates { switch update { case .append(let spaceRooms): - spaces.append(contentsOf: spaceRooms.map(SpaceRoomProxy.init)) + spaces.append(contentsOf: spaceRooms.map { SpaceRoomProxy(spaceRoom: $0, parent: nil) }) case .clear: spaces.removeAll() case .pushFront(let spaceRoom): - spaces.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: 0) + spaces.insert(SpaceRoomProxy(spaceRoom: spaceRoom, parent: nil), at: 0) case .pushBack(let spaceRoom): - spaces.append(SpaceRoomProxy(spaceRoom: spaceRoom)) + spaces.append(SpaceRoomProxy(spaceRoom: spaceRoom, parent: nil)) case .popFront: spaces.removeFirst() case .popBack: spaces.removeLast() case .insert(let index, let spaceRoom): - spaces.insert(SpaceRoomProxy(spaceRoom: spaceRoom), at: Int(index)) + spaces.insert(SpaceRoomProxy(spaceRoom: spaceRoom, parent: nil), at: Int(index)) case .set(let index, let spaceRoom): - spaces[Int(index)] = SpaceRoomProxy(spaceRoom: spaceRoom) + spaces[Int(index)] = SpaceRoomProxy(spaceRoom: spaceRoom, parent: nil) case .remove(let index): spaces.remove(at: Int(index)) case .truncate(let length): spaces.removeSubrange(Int(length).. { get } - func spaceRoomList(spaceID: String) async -> Result + func spaceRoomList(spaceID: String, parent: SpaceRoomProxyProtocol?) async -> Result } diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-en-GB-0.png index 77ae2b7e7..95c3cab00 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d89f971df09420eeb3e2393d12851c50da0896366fd914df6e50f8525b1963bc -size 207443 +oid sha256:807aa8e11948c203afd2deb242544db922d2b9fa5f03bfb5e51a065111da287b +size 207287 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-pseudo-0.png index 9a908fa58..f13067657 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80d43f3c8bd54048177b925efe184e6324da54a6c342ed2f5629983a15ec946a -size 223500 +oid sha256:95bceb140bbd1058309c452ed10a2793786d3920d56b560b064bd42b168d8db2 +size 224095 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-en-GB-0.png index 826a43d0f..0a07006ac 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11b7484b43434f0d598cc596e7eaaa9d898d25b3aba4dfe9d05bdc78ea9b8187 -size 138715 +oid sha256:3937567a4f7c207808f34ca90da2235499b12125bdcab7265a4306952148656d +size 138754 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-pseudo-0.png index 3ca2eefc6..31bd7b9d2 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceHeaderView.iPhone-16-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e5ea7da5f53f16d9d7eba70450c61ef7ec6b93f70148d32b0152ffa6ec211c33 -size 164457 +oid sha256:fcfd2f3de9d2bc68fe60f938a7f547b9db72ebca2b4dce6d70295e3c41c031a4 +size 164599 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-en-GB-0.png index 3f0c2b8c0..984ecdd3e 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54368559609ff14224342f399d05e2a5dbd2a8955aaf4154d53b6f0ac356dd3a -size 237461 +oid sha256:c8fb30078446367dea1b3b82dcb666fd6feefd209538d33497069e6b093f3169 +size 237815 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-pseudo-0.png index 13cf6ae6f..afbb724eb 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:074fc2ca164c28f15ab817ebee9f8ec74eb1cb99737996777e03b65873935e5e -size 278733 +oid sha256:5027349437978cdc95f908a0101186b8760c1da5b69cf4e5edec867b41168065 +size 279853 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-en-GB-0.png index 78a176bce..50af892c3 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:37ff651fc4d7b3e559df8148424d5f58935aa885fd51795db37e8ac687ceaf20 -size 173995 +oid sha256:cbfed0d2b08d41fdbd6ff60c281cb5d6ec3e80bbdc6a59329a83d6ea9d4c318e +size 173900 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-pseudo-0.png index 874bc9c97..c93a093af 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceRoomCell.iPhone-16-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e8846578b4730e1fb88c183078eb2be0fe707f528ec3ae9dd56a4720f5caa2a -size 197153 +oid sha256:ff137a6fbde88a171d53a6ac84d0b865e045d6e4a20a9391b04752fd50a4aab3 +size 197663 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-en-GB-0.png index be07f3192..4bad06a59 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa43fefcbe0406d7c84752152b5f4ad6951175fcc98a9fb48b0f6cad24d0f012 -size 242481 +oid sha256:dd3dd3c0a55de039b42e2e482961a0bdb10b620fb9ec61bce3aeb5b21ace9673 +size 242555 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-pseudo-0.png index 83e5b74c5..6f97f2e8f 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:949fa7494236c24c00438329892fb75750eb08b310bf1c4e56e918e8a68feec4 -size 280034 +oid sha256:9566d9dad78a0543f67888d1b71b62867872199c15e93773f0d77ee1eb9a6d14 +size 282042 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-en-GB-0.png index 5010a6c09..36c9f4ac6 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80f8c4e7b7c90e6f6ef159c7642aaed70f93f4788686d39e6518f20b98e7f5ab -size 187209 +oid sha256:d52a23968f190f7e5d09ef0c5ee88753cbafbb62a50df806cc125029f058f716 +size 187280 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-pseudo-0.png index 9823ff0a4..30f45fe42 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/spaceScreen.iPhone-16-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75524c40db1a8c622b3a37cde5ac93c022b44f807e5d18b986b906fe6e47d2e8 -size 207423 +oid sha256:f9ee877dbaac15c99f1a15b6efb40b5704c149ec1e3ba39e3ebc955943e6866d +size 208759 diff --git a/UnitTests/Sources/SpaceListScreenViewModelTests.swift b/UnitTests/Sources/SpaceListScreenViewModelTests.swift index d7bcf9863..66dae4041 100644 --- a/UnitTests/Sources/SpaceListScreenViewModelTests.swift +++ b/UnitTests/Sources/SpaceListScreenViewModelTests.swift @@ -72,7 +72,7 @@ class SpaceListScreenViewModelTests: XCTestCase { ]) spaceServiceProxy = SpaceServiceProxyMock(.init()) spaceServiceProxy.joinedSpacesPublisher = joinedSpacesSubject.asCurrentValuePublisher() - spaceServiceProxy.spaceRoomListSpaceIDClosure = { [joinedSpacesSubject] spaceID in + spaceServiceProxy.spaceRoomListSpaceIDParentClosure = { [joinedSpacesSubject] spaceID, _ in guard let spaceRoomProxy = joinedSpacesSubject?.value.first(where: { $0.id == spaceID }) else { return .failure(.missingSpace) } return .success(SpaceRoomListProxyMock(.init(spaceRoomProxy: spaceRoomProxy))) } diff --git a/UnitTests/Sources/SpaceScreenViewModelTests.swift b/UnitTests/Sources/SpaceScreenViewModelTests.swift index 368db5d48..c53b3f244 100644 --- a/UnitTests/Sources/SpaceScreenViewModelTests.swift +++ b/UnitTests/Sources/SpaceScreenViewModelTests.swift @@ -200,7 +200,7 @@ class SpaceScreenViewModelTests: XCTestCase { paginationResponses: paginationResponses)) let spaceServiceProxy = SpaceServiceProxyMock(.init()) - spaceServiceProxy.spaceRoomListSpaceIDClosure = { [mockSpaceRooms] spaceID in + spaceServiceProxy.spaceRoomListSpaceIDParentClosure = { [mockSpaceRooms] spaceID, _ in guard let spaceRoomProxy = mockSpaceRooms.first(where: { $0.id == spaceID }) else { return .failure(.missingSpace) } return .success(SpaceRoomListProxyMock(.init(spaceRoomProxy: spaceRoomProxy))) }