From 0693dbaca8305acee0b72f9ac135a5999cd17993 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 25 Sep 2025 18:44:57 +0100 Subject: [PATCH 1/4] Show space invites in the room list. # Conflicts: # PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png # PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png # PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png # PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png --- .../Mocks/RoomSummaryProviderMock.swift | 11 +++++ .../View/HomeScreenInviteCell.swift | 44 +++++++++++++------ .../View/HomeScreenKnockedCell.swift | 2 + .../Room/RoomSummary/RoomSummary.swift | 11 +++-- .../RoomSummary/RoomSummaryProvider.swift | 18 +++++--- .../homeScreenInviteCell.iPad-en-GB-0.png | 4 +- .../homeScreenInviteCell.iPad-pseudo-0.png | 4 +- ...homeScreenInviteCell.iPhone-16-en-GB-0.png | 4 +- ...omeScreenInviteCell.iPhone-16-pseudo-0.png | 4 +- UnitTests/Sources/HomeScreenRoomTests.swift | 1 + UnitTests/Sources/LoggingTests.swift | 1 + UnitTests/Sources/RoomSummaryTests.swift | 28 +++++++++--- 12 files changed, 94 insertions(+), 38 deletions(-) diff --git a/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift b/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift index b5b79f14f6..3bdb21e50c 100644 --- a/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift +++ b/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift @@ -76,6 +76,7 @@ extension RoomSummary { joinRequestType: nil, name: name, isDirect: false, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -101,6 +102,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Foundation 🔭🪐🌌", isDirect: false, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -121,6 +123,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Foundation and Empire", isDirect: false, + isSpace: false, avatarURL: .mockMXCAvatar, heroes: [], activeMembersCount: 0, @@ -141,6 +144,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Second Foundation", isDirect: false, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -161,6 +165,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Foundation's Edge", isDirect: false, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -181,6 +186,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Foundation and Earth", isDirect: true, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -201,6 +207,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Prelude to Foundation", isDirect: true, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -221,6 +228,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Tombstoned", isDirect: false, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -241,6 +249,7 @@ extension Array where Element == RoomSummary { joinRequestType: nil, name: "Unknown", isDirect: false, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, @@ -294,6 +303,7 @@ extension Array where Element == RoomSummary { joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie), name: "First room", isDirect: false, + isSpace: false, avatarURL: .mockMXCAvatar, heroes: [], activeMembersCount: 0, @@ -314,6 +324,7 @@ extension Array where Element == RoomSummary { joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie), name: "Second room", isDirect: true, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift index 2067e19403..a3fb27aebb 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift @@ -155,23 +155,34 @@ struct HomeScreenInviteCell_Previews: PreviewProvider, TestablePreview { static var previews: some View { VStack(spacing: 0) { HomeScreenInviteCell(room: .dmInvite, - context: makeViewModel().context, hideInviteAvatars: false) - - HomeScreenInviteCell(room: .dmInvite, - context: makeViewModel().context, hideInviteAvatars: false) + context: makeViewModel().context, + hideInviteAvatars: false) HomeScreenInviteCell(room: .roomInvite(), - context: makeViewModel().context, hideInviteAvatars: false) + context: makeViewModel().context, + hideInviteAvatars: false) - HomeScreenInviteCell(room: .roomInvite(), - context: makeViewModel().context, hideInviteAvatars: false) + HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org", + avatarURL: .mockMXCAvatar), + context: makeViewModel().context, + hideInviteAvatars: false) + + // Not the final design, may get its own cell type entirely. + HomeScreenInviteCell(room: .roomInvite(name: "Awesome Space", + isSpace: true, + alias: "#footest:somewhere.org", + avatarURL: .mockMXCAvatar), + context: makeViewModel().context, + hideInviteAvatars: false) + + HomeScreenInviteCell(room: .roomInvite(name: "Hidden Avatars", + avatarURL: .mockMXCAvatar), + context: makeViewModel().context, + hideInviteAvatars: true) - HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org", avatarURL: .mockMXCAvatar), - context: makeViewModel().context, hideInviteAvatars: false) - HomeScreenInviteCell(room: .roomInvite(alias: "#footest-hidden-avatars:somewhere.org", avatarURL: .mockMXCAvatar), - context: makeViewModel().context, hideInviteAvatars: true) HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org"), - context: makeViewModel().context, hideInviteAvatars: false) + context: makeViewModel().context, + hideInviteAvatars: false) .dynamicTypeSize(.accessibility1) .previewDisplayName("Aliased room (AX1)") } @@ -204,6 +215,7 @@ private extension HomeScreenRoom { joinRequestType: .invite(inviter: inviter), name: "Some Guy", isDirect: true, + isSpace: false, avatarURL: nil, heroes: [.init(userID: "@someone:somewhere.com")], activeMembersCount: 0, @@ -223,7 +235,10 @@ private extension HomeScreenRoom { return .init(summary: summary, hideUnreadMessagesBadge: false) } - static func roomInvite(alias: String? = nil, avatarURL: URL? = nil) -> HomeScreenRoom { + static func roomInvite(name: String = "Awesome Room", + isSpace: Bool = false, + alias: String? = nil, + avatarURL: URL? = nil) -> HomeScreenRoom { let inviter = RoomMemberProxyMock() inviter.displayName = "Luca" inviter.userID = "@jack:somewhi.nl" @@ -232,8 +247,9 @@ private extension HomeScreenRoom { let summary = RoomSummary(room: RoomSDKMock(), id: "@someone:somewhere.com", joinRequestType: .invite(inviter: inviter), - name: "Awesome Room", + name: name, isDirect: false, + isSpace: isSpace, avatarURL: avatarURL, heroes: [.init(userID: "@someone:somewhere.com")], activeMembersCount: 0, diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift index b4a10692ef..dae48f2dfb 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenKnockedCell.swift @@ -149,6 +149,7 @@ private extension HomeScreenRoom { joinRequestType: .invite(inviter: inviter), name: "Some Guy", isDirect: true, + isSpace: false, avatarURL: nil, heroes: [.init(userID: "@someone:somewhere.com")], activeMembersCount: 0, @@ -179,6 +180,7 @@ private extension HomeScreenRoom { joinRequestType: .invite(inviter: inviter), name: "Awesome Room", isDirect: false, + isSpace: false, avatarURL: avatarURL, heroes: [.init(userID: "@someone:somewhere.com")], activeMembersCount: 0, diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummary.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummary.swift index 72733abad1..76adb13cb9 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummary.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummary.swift @@ -37,6 +37,7 @@ struct RoomSummary { let name: String let isDirect: Bool + let isSpace: Bool let avatarURL: URL? let heroes: [UserProfileProxy] @@ -107,6 +108,7 @@ extension RoomSummary { let string = "\(settingsMode) - messages: \(hasUnreadMessages) - mentions: \(hasUnreadMentions) - notifications: \(hasUnreadNotifications)" name = string isDirect = true + isSpace = false avatarURL = nil heroes = [] @@ -134,12 +136,9 @@ extension RoomSummary { return .tombstoned } - // NOTE: The check for isSpace isn't implemented yet, waiting to see - // whether we end up with a different type for spaces in the room list. - // - // Don't forget to add a test when you remove this comment 😄 - - if isDirect, avatarURL == nil, heroes.count == 1 { + if isSpace { + return .space(id: id, name: name, avatarURL: avatarURL) + } else if isDirect, avatarURL == nil, heroes.count == 1 { return .heroes(heroes) } else { return .room(id: id, name: name, avatarURL: avatarURL) diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index d909a86e80..832614a74b 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -118,19 +118,26 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { } func setFilter(_ filter: RoomSummaryProviderFilter) { + let baseFilter: [RoomListEntriesDynamicFilterKind] = if appSettings.spacesEnabled { + [.any(filters: [.all(filters: [.nonSpace, .nonLeft]), + .all(filters: [.space, .invite])]), + .deduplicateVersions] + } else { + [.nonLeft, .nonSpace, .deduplicateVersions] + } + switch filter { case .excludeAll: _ = listUpdatesSubscriptionResult?.controller().setFilter(kind: .none) case let .search(query): - let filters: [RoomListEntriesDynamicFilterKind] = if appSettings.fuzzyRoomListSearchEnabled { - [.fuzzyMatchRoomName(pattern: query), .nonLeft, .nonSpace, .deduplicateVersions] + let filters = if appSettings.fuzzyRoomListSearchEnabled { + [.fuzzyMatchRoomName(pattern: query)] + baseFilter } else { - [.normalizedMatchRoomName(pattern: query), .nonLeft, .nonSpace, .deduplicateVersions] + [.normalizedMatchRoomName(pattern: query)] + baseFilter } _ = listUpdatesSubscriptionResult?.controller().setFilter(kind: .all(filters: filters)) case let .all(filters): - var rustFilters = filters.map(\.rustFilter) - rustFilters.append(contentsOf: [.nonLeft, .nonSpace, .deduplicateVersions]) + var rustFilters = filters.map(\.rustFilter) + baseFilter if !filters.contains(.lowPriority), appSettings.lowPriorityFilterEnabled { rustFilters.append(.nonLowPriority) @@ -277,6 +284,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { joinRequestType: joinRequestType, name: roomInfo.displayName ?? roomInfo.id, isDirect: roomInfo.isDirect, + isSpace: roomInfo.isSpace, avatarURL: roomInfo.avatarUrl.flatMap(URL.init(string:)), heroes: roomInfo.heroes.map(UserProfileProxy.init), activeMembersCount: UInt(roomInfo.activeMembersCount), diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png index 0b97b7fd56..af83396924 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f1ccbe7325a061b9e4172023ad488e3bc84d1bc78258332cef1d001fe0c981d -size 285976 +oid sha256:4a547ea718112cc8ed74b5ed33409c30ee83aa7e0a2fd6f47f7cc84b7dbdccf3 +size 279255 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png index 47be7f958a..f27c9ed23a 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14e84577293fa0d99fa5e47e64f56abdb35ddcb078dc36c4003afc38e35d268c -size 305735 +oid sha256:3764d55eab380b2a58c911ebda924ed76ada164a3a2cd642fd5a400f99007bc6 +size 298096 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png index 63ea6a73ea..13578a11cb 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a06af6bc07ecafee0421eeff23e5b094bf5adbfd6cf2690dfc8c34ccad916c7 -size 230104 +oid sha256:437bdc042f3d3c00bb42cacf09390fb7f9fe4d55cb2903aed7d62e1f5d83d335 +size 231601 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png index a16ac199b3..d0a2e12f80 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e25479532f86cb78dbf03fc8f48429a6e090614728bb87c6a40edf521660803 -size 314381 +oid sha256:e282d7972878f12a7532f31258a79eed122897f8ce873ea27a4946d4d0a65587 +size 308931 diff --git a/UnitTests/Sources/HomeScreenRoomTests.swift b/UnitTests/Sources/HomeScreenRoomTests.swift index b15bbc1ef4..648ae28444 100644 --- a/UnitTests/Sources/HomeScreenRoomTests.swift +++ b/UnitTests/Sources/HomeScreenRoomTests.swift @@ -25,6 +25,7 @@ class HomeScreenRoomTests: XCTestCase { joinRequestType: nil, name: "Test room", isDirect: false, + isSpace: false, avatarURL: nil, heroes: [], activeMembersCount: 0, diff --git a/UnitTests/Sources/LoggingTests.swift b/UnitTests/Sources/LoggingTests.swift index be6534cbff..c4a4003a93 100644 --- a/UnitTests/Sources/LoggingTests.swift +++ b/UnitTests/Sources/LoggingTests.swift @@ -75,6 +75,7 @@ class LoggingTests: XCTestCase { joinRequestType: nil, name: roomName, isDirect: true, + isSpace: false, avatarURL: nil, heroes: [.init(userID: "", displayName: heroName)], activeMembersCount: 0, diff --git a/UnitTests/Sources/RoomSummaryTests.swift b/UnitTests/Sources/RoomSummaryTests.swift index 410b9ad4c6..6f7f43766d 100644 --- a/UnitTests/Sources/RoomSummaryTests.swift +++ b/UnitTests/Sources/RoomSummaryTests.swift @@ -15,7 +15,7 @@ class RoomSummaryTests: XCTestCase { let heroes = [UserProfileProxy(userID: "hero_1", displayName: "Hero 1", avatarURL: "mxc://hs.tld/user/avatar")] func testRoomAvatar() { - let details = makeSummary(isDirect: false, hasRoomAvatar: true, isTombstoned: false) + let details = makeSummary(isDirect: false, isSpace: false, hasRoomAvatar: true, isTombstoned: false) switch details.avatar { case .room(let id, let name, let avatarURL): @@ -32,7 +32,7 @@ class RoomSummaryTests: XCTestCase { } func testDMAvatarSet() { - let details = makeSummary(isDirect: true, hasRoomAvatar: true, isTombstoned: false) + let details = makeSummary(isDirect: true, isSpace: false, hasRoomAvatar: true, isTombstoned: false) switch details.avatar { case .room(let id, let name, let avatarURL): @@ -49,7 +49,7 @@ class RoomSummaryTests: XCTestCase { } func testDMAvatarNotSet() { - let details = makeSummary(isDirect: true, hasRoomAvatar: false, isTombstoned: false) + let details = makeSummary(isDirect: true, isSpace: false, hasRoomAvatar: false, isTombstoned: false) switch details.avatar { case .room: @@ -63,20 +63,38 @@ class RoomSummaryTests: XCTestCase { } } + func testSpaceAvatar() { + let details = makeSummary(isDirect: false, isSpace: true, hasRoomAvatar: true, isTombstoned: false) + + switch details.avatar { + case .room: + XCTFail("A space shouldn't use a room avatar.") + case .heroes: + XCTFail("A room shouldn't use the heroes for its avatar.") + case .space(let id, let name, let avatarURL): + XCTAssertEqual(id, roomDetails.id) + XCTAssertEqual(name, roomDetails.name) + XCTAssertEqual(avatarURL, roomDetails.avatarURL) + case .tombstoned: + XCTFail("A room shouldn't use the tombstone for its avatar.") + } + } + func testTombstonedAvatar() { - let details = makeSummary(isDirect: false, hasRoomAvatar: true, isTombstoned: true) + let details = makeSummary(isDirect: false, isSpace: false, hasRoomAvatar: true, isTombstoned: true) XCTAssertEqual(details.avatar, .tombstoned) } // MARK: - Helpers - func makeSummary(isDirect: Bool, hasRoomAvatar: Bool, isTombstoned: Bool) -> RoomSummary { + func makeSummary(isDirect: Bool, isSpace: Bool, hasRoomAvatar: Bool, isTombstoned: Bool) -> RoomSummary { RoomSummary(room: .init(noPointer: .init()), id: roomDetails.id, joinRequestType: nil, name: roomDetails.name, isDirect: isDirect, + isSpace: isSpace, avatarURL: hasRoomAvatar ? roomDetails.avatarURL : nil, heroes: heroes, activeMembersCount: 0, From 386aaccae856fd1254ae2445c8f49cb0f567511a Mon Sep 17 00:00:00 2001 From: Doug Date: Fri, 26 Sep 2025 11:54:04 +0100 Subject: [PATCH 2/4] Update the SDK. --- ElementX.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../Mocks/Generated/SDKGeneratedMocks.swift | 211 +++++++++++++++++- .../RoomSummary/RoomEventStringBuilder.swift | 2 + .../RoomTimelineItemFactory.swift | 2 + project.yml | 2 +- 6 files changed, 218 insertions(+), 5 deletions(-) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 6ddeb74d20..887c4abb9d 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -9364,7 +9364,7 @@ repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = "25.09.19-2"; + version = 25.09.26; }; }; 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d0cda640ec..7af40e8ee4 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -150,8 +150,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/element-hq/matrix-rust-components-swift", "state" : { - "revision" : "6da13e26194148a51ff21024df5946e1641be209", - "version" : "25.9.19-2" + "revision" : "c79dc9374e580b74084535ebe09925764939058b", + "version" : "25.9.26" } }, { diff --git a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift index 751d344933..0a52ec542e 100644 --- a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift @@ -1,4 +1,4 @@ -// Generated using Sourcery 2.2.7 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 2.3.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable all @@ -8149,6 +8149,75 @@ open class EncryptionSDKMock: MatrixRustSDK.Encryption, @unchecked Sendable { } } + //MARK: - hasDevicesToVerifyAgainst + + open var hasDevicesToVerifyAgainstThrowableError: Error? + var hasDevicesToVerifyAgainstUnderlyingCallsCount = 0 + open var hasDevicesToVerifyAgainstCallsCount: Int { + get { + if Thread.isMainThread { + return hasDevicesToVerifyAgainstUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = hasDevicesToVerifyAgainstUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + hasDevicesToVerifyAgainstUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + hasDevicesToVerifyAgainstUnderlyingCallsCount = newValue + } + } + } + } + open var hasDevicesToVerifyAgainstCalled: Bool { + return hasDevicesToVerifyAgainstCallsCount > 0 + } + + var hasDevicesToVerifyAgainstUnderlyingReturnValue: Bool! + open var hasDevicesToVerifyAgainstReturnValue: Bool! { + get { + if Thread.isMainThread { + return hasDevicesToVerifyAgainstUnderlyingReturnValue + } else { + var returnValue: Bool? = nil + DispatchQueue.main.sync { + returnValue = hasDevicesToVerifyAgainstUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + hasDevicesToVerifyAgainstUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + hasDevicesToVerifyAgainstUnderlyingReturnValue = newValue + } + } + } + } + open var hasDevicesToVerifyAgainstClosure: (() async throws -> Bool)? + + open override func hasDevicesToVerifyAgainst() async throws -> Bool { + if let error = hasDevicesToVerifyAgainstThrowableError { + throw error + } + hasDevicesToVerifyAgainstCallsCount += 1 + if let hasDevicesToVerifyAgainstClosure = hasDevicesToVerifyAgainstClosure { + return try await hasDevicesToVerifyAgainstClosure() + } else { + return hasDevicesToVerifyAgainstReturnValue + } + } + //MARK: - isLastDevice open var isLastDeviceThrowableError: Error? @@ -14289,6 +14358,81 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable { } } + //MARK: - loadOrFetchEvent + + open var loadOrFetchEventEventIdThrowableError: Error? + var loadOrFetchEventEventIdUnderlyingCallsCount = 0 + open var loadOrFetchEventEventIdCallsCount: Int { + get { + if Thread.isMainThread { + return loadOrFetchEventEventIdUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = loadOrFetchEventEventIdUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + loadOrFetchEventEventIdUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + loadOrFetchEventEventIdUnderlyingCallsCount = newValue + } + } + } + } + open var loadOrFetchEventEventIdCalled: Bool { + return loadOrFetchEventEventIdCallsCount > 0 + } + open var loadOrFetchEventEventIdReceivedEventId: String? + open var loadOrFetchEventEventIdReceivedInvocations: [String] = [] + + var loadOrFetchEventEventIdUnderlyingReturnValue: TimelineEvent! + open var loadOrFetchEventEventIdReturnValue: TimelineEvent! { + get { + if Thread.isMainThread { + return loadOrFetchEventEventIdUnderlyingReturnValue + } else { + var returnValue: TimelineEvent? = nil + DispatchQueue.main.sync { + returnValue = loadOrFetchEventEventIdUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + loadOrFetchEventEventIdUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + loadOrFetchEventEventIdUnderlyingReturnValue = newValue + } + } + } + } + open var loadOrFetchEventEventIdClosure: ((String) async throws -> TimelineEvent)? + + open override func loadOrFetchEvent(eventId: String) async throws -> TimelineEvent { + if let error = loadOrFetchEventEventIdThrowableError { + throw error + } + loadOrFetchEventEventIdCallsCount += 1 + loadOrFetchEventEventIdReceivedEventId = eventId + DispatchQueue.main.async { + self.loadOrFetchEventEventIdReceivedInvocations.append(eventId) + } + if let loadOrFetchEventEventIdClosure = loadOrFetchEventEventIdClosure { + return try await loadOrFetchEventEventIdClosure(eventId) + } else { + return loadOrFetchEventEventIdReturnValue + } + } + //MARK: - markAsRead open var markAsReadReceiptTypeThrowableError: Error? @@ -25317,6 +25461,71 @@ open class TimelineEventSDKMock: MatrixRustSDK.TimelineEvent, @unchecked Sendabl } } + //MARK: - threadRootEventId + + var threadRootEventIdUnderlyingCallsCount = 0 + open var threadRootEventIdCallsCount: Int { + get { + if Thread.isMainThread { + return threadRootEventIdUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = threadRootEventIdUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + threadRootEventIdUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + threadRootEventIdUnderlyingCallsCount = newValue + } + } + } + } + open var threadRootEventIdCalled: Bool { + return threadRootEventIdCallsCount > 0 + } + + var threadRootEventIdUnderlyingReturnValue: String? + open var threadRootEventIdReturnValue: String? { + get { + if Thread.isMainThread { + return threadRootEventIdUnderlyingReturnValue + } else { + var returnValue: String?? = nil + DispatchQueue.main.sync { + returnValue = threadRootEventIdUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + threadRootEventIdUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + threadRootEventIdUnderlyingReturnValue = newValue + } + } + } + } + open var threadRootEventIdClosure: (() -> String?)? + + open override func threadRootEventId() -> String? { + threadRootEventIdCallsCount += 1 + if let threadRootEventIdClosure = threadRootEventIdClosure { + return threadRootEventIdClosure() + } else { + return threadRootEventIdReturnValue + } + } + //MARK: - timestamp var timestampUnderlyingCallsCount = 0 diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomEventStringBuilder.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomEventStringBuilder.swift index 10d7ef1770..7ccfbd728b 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomEventStringBuilder.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomEventStringBuilder.swift @@ -55,6 +55,8 @@ struct RoomEventStringBuilder { default: L10n.commonWaitingForDecryptionKey } return prefix(errorMessage, with: displayName, isOutgoing: isOutgoing) + case .other(eventType: let eventType): + return nil // We shouldn't receive these without asking for custom event types. } case .failedToParseMessageLike, .failedToParseState: return prefix(L10n.commonUnsupportedEvent, with: displayName, isOutgoing: isOutgoing) diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift index 9f026adc7d..2cd1629108 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift @@ -40,6 +40,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { return buildRedactedTimelineItem(eventItemProxy, messageLikeContent, isOutgoing) case .unableToDecrypt(let encryptedMessage): return buildEncryptedTimelineItem(eventItemProxy, messageLikeContent, encryptedMessage, isOutgoing) + case .other(eventType: let eventType): + return nil // We shouldn't receive these without asking for custom event types. } case .failedToParseMessageLike(let eventType, let error): return buildUnsupportedTimelineItem(eventItemProxy, eventType, error, isOutgoing) diff --git a/project.yml b/project.yml index 10c81c4ba3..d35f573d45 100644 --- a/project.yml +++ b/project.yml @@ -68,7 +68,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/element-hq/matrix-rust-components-swift - exactVersion: 25.09.19-2 + exactVersion: 25.09.26 # path: ../matrix-rust-sdk Compound: path: compound-ios From 133e9923579f932be0291cb62570688e48ae9f61 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 29 Sep 2025 11:27:15 +0100 Subject: [PATCH 3/4] Rebase --- .../PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png | 4 ++-- .../PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png | 4 ++-- .../PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png | 4 ++-- .../PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png index af83396924..89e481246f 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4a547ea718112cc8ed74b5ed33409c30ee83aa7e0a2fd6f47f7cc84b7dbdccf3 -size 279255 +oid sha256:47434bcec59bcd4dac1b9ed7263ea235b7dd99f190124b738f2ddc87c9f098fc +size 280431 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png index f27c9ed23a..cdf1b2fc2a 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3764d55eab380b2a58c911ebda924ed76ada164a3a2cd642fd5a400f99007bc6 -size 298096 +oid sha256:a60f98dcc98f0ac79dcdc87fc11f05094c34445181b8f01559b4f5b28ac6e78c +size 299297 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png index 13578a11cb..3f76f9a8dc 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:437bdc042f3d3c00bb42cacf09390fb7f9fe4d55cb2903aed7d62e1f5d83d335 -size 231601 +oid sha256:7a1a22b19ce5bb8077a65937ca34d590dd5997b1d0f2ad15481e1c9ca6563d7f +size 232650 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png index d0a2e12f80..9b60958ef8 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreenInviteCell.iPhone-16-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e282d7972878f12a7532f31258a79eed122897f8ce873ea27a4946d4d0a65587 -size 308931 +oid sha256:d9794b3f11c6c35102a184b2cfb1c849a6741412da784059e27b7818a071936d +size 309996 From cee56871afbe2f3da1f42e39c34ce14bdd425f8c Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 29 Sep 2025 11:45:51 +0100 Subject: [PATCH 4/4] PR comments. --- .../View/HomeScreenInviteCell.swift | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift index a3fb27aebb..711d16f2ab 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift @@ -158,29 +158,29 @@ struct HomeScreenInviteCell_Previews: PreviewProvider, TestablePreview { context: makeViewModel().context, hideInviteAvatars: false) - HomeScreenInviteCell(room: .roomInvite(), + HomeScreenInviteCell(room: .invite(), context: makeViewModel().context, hideInviteAvatars: false) - HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org", - avatarURL: .mockMXCAvatar), + HomeScreenInviteCell(room: .invite(alias: "#footest:somewhere.org", + avatarURL: .mockMXCAvatar), context: makeViewModel().context, hideInviteAvatars: false) // Not the final design, may get its own cell type entirely. - HomeScreenInviteCell(room: .roomInvite(name: "Awesome Space", - isSpace: true, - alias: "#footest:somewhere.org", - avatarURL: .mockMXCAvatar), + HomeScreenInviteCell(room: .invite(name: "Awesome Space", + isSpace: true, + alias: "#footest:somewhere.org", + avatarURL: .mockMXCAvatar), context: makeViewModel().context, hideInviteAvatars: false) - HomeScreenInviteCell(room: .roomInvite(name: "Hidden Avatars", - avatarURL: .mockMXCAvatar), + HomeScreenInviteCell(room: .invite(name: "Hidden Avatars", + avatarURL: .mockMXCAvatar), context: makeViewModel().context, hideInviteAvatars: true) - HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org"), + HomeScreenInviteCell(room: .invite(alias: "#footest:somewhere.org"), context: makeViewModel().context, hideInviteAvatars: false) .dynamicTypeSize(.accessibility1) @@ -235,10 +235,10 @@ private extension HomeScreenRoom { return .init(summary: summary, hideUnreadMessagesBadge: false) } - static func roomInvite(name: String = "Awesome Room", - isSpace: Bool = false, - alias: String? = nil, - avatarURL: URL? = nil) -> HomeScreenRoom { + static func invite(name: String = "Awesome Room", + isSpace: Bool = false, + alias: String? = nil, + avatarURL: URL? = nil) -> HomeScreenRoom { let inviter = RoomMemberProxyMock() inviter.displayName = "Luca" inviter.userID = "@jack:somewhi.nl"