diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 7a5f8cb6d..1b5216bb5 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -10349,7 +10349,7 @@ repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = 26.07.08; + version = 26.07.14; }; }; 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2861cd53b..efd3fc8b9 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -167,8 +167,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/element-hq/matrix-rust-components-swift", "state" : { - "revision" : "b286aeac2774f516839abcb91bbac1450188a591", - "version" : "26.7.8" + "revision" : "c9d9e2a718a8d55a750f37c4f44b7571d03bb325", + "version" : "26.7.14" } }, { diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 663667b30..fafde662c 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -3316,6 +3316,76 @@ nonisolated class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable { return removeUserAvatarReturnValue } } + //MARK: - setUserStatus + + private let setUserStatusCallsCountLock = NSLock() + private nonisolated(unsafe) var setUserStatusUnderlyingCallsCount = 0 + var setUserStatusCallsCount: Int { + get { setUserStatusCallsCountLock.withLock { setUserStatusUnderlyingCallsCount } } + set { setUserStatusCallsCountLock.withLock { setUserStatusUnderlyingCallsCount = newValue } } + } + var setUserStatusCalled: Bool { + return setUserStatusCallsCount > 0 + } + private let setUserStatusReceivedStatusLock = NSLock() + private nonisolated(unsafe) var setUserStatusUnderlyingReceivedStatus: UserStatus.Raw? + var setUserStatusReceivedStatus: UserStatus.Raw? { + get { setUserStatusReceivedStatusLock.withLock { setUserStatusUnderlyingReceivedStatus } } + set { setUserStatusReceivedStatusLock.withLock { setUserStatusUnderlyingReceivedStatus = newValue } } + } + private let setUserStatusReceivedInvocationsLock = NSLock() + private nonisolated(unsafe) var setUserStatusUnderlyingReceivedInvocations: [UserStatus.Raw] = [] + var setUserStatusReceivedInvocations: [UserStatus.Raw] { + get { setUserStatusReceivedInvocationsLock.withLock { setUserStatusUnderlyingReceivedInvocations } } + set { setUserStatusReceivedInvocationsLock.withLock { setUserStatusUnderlyingReceivedInvocations = newValue } } + } + + private let setUserStatusReturnValueLock = NSLock() + private nonisolated(unsafe) var setUserStatusUnderlyingReturnValue: Result! + var setUserStatusReturnValue: Result! { + get { setUserStatusReturnValueLock.withLock { setUserStatusUnderlyingReturnValue } } + set { setUserStatusReturnValueLock.withLock { setUserStatusUnderlyingReturnValue = newValue } } + } + nonisolated(unsafe) var setUserStatusClosure: ((UserStatus.Raw) async -> Result)? + + @concurrent func setUserStatus(_ status: UserStatus.Raw) async -> Result { + setUserStatusCallsCountLock.withLock { setUserStatusUnderlyingCallsCount += 1 } + setUserStatusReceivedStatus = status + setUserStatusReceivedInvocationsLock.withLock { setUserStatusUnderlyingReceivedInvocations.append(status) } + if let setUserStatusClosure = setUserStatusClosure { + return await setUserStatusClosure(status) + } else { + return setUserStatusReturnValue + } + } + //MARK: - removeUserStatus + + private let removeUserStatusCallsCountLock = NSLock() + private nonisolated(unsafe) var removeUserStatusUnderlyingCallsCount = 0 + var removeUserStatusCallsCount: Int { + get { removeUserStatusCallsCountLock.withLock { removeUserStatusUnderlyingCallsCount } } + set { removeUserStatusCallsCountLock.withLock { removeUserStatusUnderlyingCallsCount = newValue } } + } + var removeUserStatusCalled: Bool { + return removeUserStatusCallsCount > 0 + } + + private let removeUserStatusReturnValueLock = NSLock() + private nonisolated(unsafe) var removeUserStatusUnderlyingReturnValue: Result! + var removeUserStatusReturnValue: Result! { + get { removeUserStatusReturnValueLock.withLock { removeUserStatusUnderlyingReturnValue } } + set { removeUserStatusReturnValueLock.withLock { removeUserStatusUnderlyingReturnValue = newValue } } + } + nonisolated(unsafe) var removeUserStatusClosure: (() async -> Result)? + + @concurrent func removeUserStatus() async -> Result { + removeUserStatusCallsCountLock.withLock { removeUserStatusUnderlyingCallsCount += 1 } + if let removeUserStatusClosure = removeUserStatusClosure { + return await removeUserStatusClosure() + } else { + return removeUserStatusReturnValue + } + } //MARK: - linkNewDeviceService private let linkNewDeviceServiceCallsCountLock = NSLock() diff --git a/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift b/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift index 85976bfa9..d15be42b8 100644 --- a/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift +++ b/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift @@ -79,6 +79,8 @@ private extension RoomMember { self.init(userId: proxy.userID, displayName: proxy.displayName, avatarUrl: proxy.avatarURL?.absoluteString, + status: proxy.status.raw?.rustValue, + call: proxy.status.call?.rustValue, membership: proxy.membership, isNameAmbiguous: proxy.disambiguatedDisplayName != proxy.displayName, powerLevel: proxy.powerLevel.rustPowerLevel, diff --git a/ElementX/Sources/Mocks/UserProfile+Mock.swift b/ElementX/Sources/Mocks/UserProfile+Mock.swift index 5a80d2922..6c26f6002 100644 --- a/ElementX/Sources/Mocks/UserProfile+Mock.swift +++ b/ElementX/Sources/Mocks/UserProfile+Mock.swift @@ -44,18 +44,18 @@ extension UserProfile { nonisolated extension UserStatus { static var mockCall: UserStatus { - .init(userSet: nil, call: .init(startDate: nil)) + .init(raw: nil, call: .init(joinedDate: nil)) } static var mockFocussing: UserStatus { - .init(userSet: .init(text: "Focussing", emoji: "🧑‍💻"), call: nil) + .init(raw: .init(text: "Focussing", emoji: "🧑‍💻"), call: nil) } static var mockHoliday: UserStatus { - .init(userSet: .init(text: "Holiday", emoji: "🏝️"), call: nil) + .init(raw: .init(text: "Holiday", emoji: "🏝️"), call: nil) } static func mock(text: String, emoji: Character) -> UserStatus { - .init(userSet: .init(text: text, emoji: emoji), call: nil) + .init(raw: .init(text: text, emoji: emoji), call: nil) } } diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index 4e715e529..743f3ec94 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -710,9 +710,7 @@ class ClientProxy: ClientProxyProtocol { func setUserDisplayName(_ name: String) async -> Result { do { try await client.setDisplayName(name: name) - Task { - await self.loadUserProfile() - } + Task { await self.loadUserProfile() } return .success(()) } catch { MXLog.error("Failed setting user display name with error: \(error)") @@ -729,9 +727,7 @@ class ClientProxy: ClientProxyProtocol { do { let data = try Data(contentsOf: imageURL) try await client.uploadAvatar(mimeType: mimeType, data: data) - Task { - await self.loadUserProfile() - } + Task { await self.loadUserProfile() } return .success(()) } catch { MXLog.error("Failed setting user avatar with error: \(error)") @@ -742,9 +738,7 @@ class ClientProxy: ClientProxyProtocol { func removeUserAvatar() async -> Result { do { try await client.removeAvatar() - Task { - await self.loadUserProfile() - } + Task { await self.loadUserProfile() } return .success(()) } catch { MXLog.error("Failed removing user avatar with error: \(error)") @@ -752,6 +746,28 @@ class ClientProxy: ClientProxyProtocol { } } + func setUserStatus(_ status: UserStatus.Raw) async -> Result { + do { + try await client.setUserStatus(status: status.rustValue) + Task { await self.loadUserProfile() } + return .success(()) + } catch { + MXLog.error("Failed setting user status with error: \(error)") + return .failure(.sdkError(error)) + } + } + + func removeUserStatus() async -> Result { + do { + try await client.clearUserStatus() + Task { await self.loadUserProfile() } + return .success(()) + } catch { + MXLog.error("Failed removing user status with error: \(error)") + return .failure(.sdkError(error)) + } + } + func linkNewDeviceService() -> LinkNewDeviceServiceProtocol { LinkNewDeviceService(handler: client.newGrantLoginWithQrCodeHandler()) } @@ -786,7 +802,7 @@ class ClientProxy: ClientProxyProtocol { func searchUsers(searchTerm: String, limit: UInt) async -> Result { do { - return try await .success(.init(sdkResults: client.searchUsers(searchTerm: searchTerm, limit: UInt64(limit)))) + return try await .success(.init(rustResults: client.searchUsers(searchTerm: searchTerm, limit: UInt64(limit)))) } catch { MXLog.error("Failed searching users with error: \(error)") return .failure(.sdkError(error)) @@ -795,7 +811,7 @@ class ClientProxy: ClientProxyProtocol { func profile(for userID: String) async -> Result { do { - return try await .success(.init(sdkUserProfile: client.getProfile(userId: userID))) + return try await .success(.init(rustUserProfile: client.getProfile(userId: userID))) } catch { MXLog.error("Failed retrieving profile for userID: \(userID) with error: \(error)") return .failure(.sdkError(error)) diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index b1def4852..5631c8552 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -215,12 +215,11 @@ protocol ClientProxyProtocol: AnyObject { func reportRoomForIdentifier(_ identifier: String, reason: String) async -> Result @discardableResult func loadUserProfile() async -> Result - func setUserDisplayName(_ name: String) async -> Result - func setUserAvatar(media: MediaInfo) async -> Result - func removeUserAvatar() async -> Result + func setUserStatus(_ status: UserStatus.Raw) async -> Result + func removeUserStatus() async -> Result func linkNewDeviceService() -> LinkNewDeviceServiceProtocol diff --git a/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift b/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift index ea70b9c26..2eb5fb6a2 100644 --- a/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift +++ b/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift @@ -190,7 +190,7 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt fileprivate func didReceiveVerificationRequest(details: MatrixRustSDK.SessionVerificationRequestDetails) { MXLog.info("Received verification request \(details)") - let details = SessionVerificationRequestDetails(senderProfile: UserProfile(sdkUserProfile: details.senderProfile), + let details = SessionVerificationRequestDetails(senderProfile: UserProfile(rustUserProfile: details.senderProfile), flowID: details.flowId, deviceID: details.deviceId, deviceDisplayName: details.deviceDisplayName, diff --git a/ElementX/Sources/Services/Timeline/Fixtures/TimelineFixtures.swift b/ElementX/Sources/Services/Timeline/Fixtures/TimelineFixtures.swift index 040ac95e0..34bd02b91 100644 --- a/ElementX/Sources/Services/Timeline/Fixtures/TimelineFixtures.swift +++ b/ElementX/Sources/Services/Timeline/Fixtures/TimelineFixtures.swift @@ -291,7 +291,11 @@ private extension TimelineItemProxy { threadRoot: nil, threadSummary: nil)) let configuration = EventTimelineItemSDKMockConfiguration(sender: "@\(sender.lowercased()):matrix.org", - senderProfile: .ready(displayName: sender, displayNameAmbiguous: false, avatarUrl: nil), + senderProfile: .ready(displayName: sender, + displayNameAmbiguous: false, + avatarUrl: nil, + status: nil, + call: nil), isOwn: isOwn, canBeRepliedTo: true, content: content) diff --git a/ElementX/Sources/Services/Timeline/TimelineItemContent/TimelineItemKeyForwarder.swift b/ElementX/Sources/Services/Timeline/TimelineItemContent/TimelineItemKeyForwarder.swift index 88d47a1a2..6f45bc80f 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItemContent/TimelineItemKeyForwarder.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItemContent/TimelineItemKeyForwarder.swift @@ -19,7 +19,7 @@ nonisolated struct TimelineItemKeyForwarder: Identifiable, Hashable { init(forwarderID: String, forwarderProfile: ProfileDetails) { switch forwarderProfile { - case let .ready(displayName, _, _): + case let .ready(displayName, _, _, _, _): self.init(id: forwarderID, displayName: displayName) default: diff --git a/ElementX/Sources/Services/Timeline/TimelineItemSender.swift b/ElementX/Sources/Services/Timeline/TimelineItemSender.swift index a4c70b1f0..0c4e19255 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItemSender.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItemSender.swift @@ -32,11 +32,12 @@ nonisolated struct TimelineItemSender: Identifiable, Hashable { init(senderID: String, senderProfile: ProfileDetails) { switch senderProfile { - case let .ready(displayName, isDisplayNameAmbiguous, avatarUrl): + case let .ready(displayName, isDisplayNameAmbiguous, avatarURL, status, call): self.init(id: senderID, displayName: displayName, isDisplayNameAmbiguous: isDisplayNameAmbiguous, - avatarURL: avatarUrl.flatMap(URL.init(string:))) + avatarURL: avatarURL.flatMap(URL.init(string:)), + status: .init(rustStatus: status, rustCall: call)) default: self.init(id: senderID, displayName: nil, diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift index 5d4157cb6..0de2c4d22 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift @@ -71,7 +71,7 @@ nonisolated struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { isOutgoing: isOutgoing) case .callInvite: return buildCallInviteTimelineItem(for: eventItemProxy) - case .rtcNotification(let callIntent, let declinedBy): + case .rtcNotification(let callIntent, let declinedBy, _, _, _): return buildCallNotificationTimelineItem(for: eventItemProxy, isDM: isDM, callIntent: callIntent, declinedBy: declinedBy) } } diff --git a/ElementX/Sources/Services/Users/UserProfile.swift b/ElementX/Sources/Services/Users/UserProfile.swift index 204add17b..cffe52c65 100644 --- a/ElementX/Sources/Services/Users/UserProfile.swift +++ b/ElementX/Sources/Services/Users/UserProfile.swift @@ -36,18 +36,18 @@ nonisolated struct UserProfile: Hashable, Identifiable { status = sender.status } - init(sdkUserProfile: MatrixRustSDK.UserProfile) { - id = sdkUserProfile.userId - displayName = sdkUserProfile.displayName - avatarURL = sdkUserProfile.avatarUrl.flatMap(URL.init(string:)) - status = .init() + init(rustUserProfile: MatrixRustSDK.UserProfile) { + id = rustUserProfile.userId + displayName = rustUserProfile.displayName + avatarURL = rustUserProfile.avatarUrl.flatMap(URL.init(string:)) + status = .init(rustStatus: rustUserProfile.status, rustCall: rustUserProfile.call) } - init(sdkRoomHero: MatrixRustSDK.RoomHero) { - id = sdkRoomHero.userId - displayName = sdkRoomHero.displayName - avatarURL = sdkRoomHero.avatarUrl.flatMap(URL.init(string:)) - status = .init() + init(rustRoomHero: MatrixRustSDK.RoomHero) { + id = rustRoomHero.userId + displayName = rustRoomHero.displayName + avatarURL = rustRoomHero.avatarUrl.flatMap(URL.init(string:)) + status = .init() // Requires https://github.com/matrix-org/matrix-rust-sdk/pull/6733 } init(member: RoomMemberProxyProtocol) { @@ -61,29 +61,36 @@ nonisolated struct UserProfile: Hashable, Identifiable { } } +// MARK: - Status + +/// A user's status, created from a combination of their manually set status along with the call status indicator. nonisolated struct UserStatus: Hashable { - /// The status manually set by the user (if any). - let userSet: UserSet? - /// The status automatically set by Element Call (while in a call). + /// The raw status that is manually set by the user (if any). + let raw: Raw? + /// The call status indicator automatically set by Element Call (while in a call). let call: Call? /// The status that should be displayed on the user's profile. - var displayed: DisplayedStatus? { + var displayed: Displayed? { // The user-set status takes precedence over the call indicator. - userSet.map { .userSet($0) } ?? call.map { .inCall($0) } + raw.map { .userSet($0) } ?? call.map { .inCall($0) } } - nonisolated struct UserSet: Hashable { + /// A status that is manually set by the user. + nonisolated struct Raw: Hashable { let text: String let emoji: Character } + /// The call status indicator automatically set by Element Call. nonisolated struct Call: Hashable { - let startDate: Date? + /// When the user joined the call, if known. + let joinedDate: Date? } - nonisolated enum DisplayedStatus: Hashable { - case userSet(UserSet) + /// The status displayed in the UI. + nonisolated enum Displayed: Hashable { + case userSet(Raw) case inCall(Call) var text: String { @@ -104,18 +111,47 @@ nonisolated struct UserStatus: Hashable { nonisolated extension UserStatus { init() { - self.init(userSet: nil, call: nil) + raw = nil + call = nil + } + + init(rustStatus: MatrixRustSDK.UserStatus?, rustCall: MatrixRustSDK.UserCall?) { + raw = rustStatus.map(Raw.init) + call = rustCall.map(Call.init) } } +nonisolated extension UserStatus.Raw { + init(rustStatus: MatrixRustSDK.UserStatus) { + text = rustStatus.text + emoji = Character(rustStatus.emoji) + } + + var rustValue: MatrixRustSDK.UserStatus { + .init(emoji: String(emoji), text: text) + } +} + +nonisolated extension UserStatus.Call { + init(rustCall: MatrixRustSDK.UserCall) { + joinedDate = rustCall.callJoinedTs.map { Date(timeIntervalSince1970: Double($0)) } + } + + var rustValue: MatrixRustSDK.UserCall { + .init(callJoinedTs: joinedDate.map { UInt64($0.timeIntervalSince1970) }) + } +} + +// MARK: - Search Results + struct SearchUsersResults { let results: [UserProfile] let limited: Bool } extension SearchUsersResults { - init(sdkResults: MatrixRustSDK.SearchUsersResults) { - results = sdkResults.results.map(UserProfile.init) - limited = sdkResults.limited + init(rustResults: MatrixRustSDK.SearchUsersResults) { + results = rustResults.results.map(UserProfile.init) + limited = rustResults.limited } } diff --git a/NSE/Sources/NotificationHandler.swift b/NSE/Sources/NotificationHandler.swift index ac7449702..8cb498f22 100644 --- a/NSE/Sources/NotificationHandler.swift +++ b/NSE/Sources/NotificationHandler.swift @@ -144,7 +144,8 @@ nonisolated class NotificationHandler { .keyVerificationKey, .keyVerificationMac, .keyVerificationDone, - .reactionContent: + .reactionContent, + .beacon: return .unsupportedShouldDiscard } case .state: diff --git a/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift b/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift index 78b5d4330..a1cc50f56 100644 --- a/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift +++ b/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift @@ -420,6 +420,28 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable { try await clearCachesSyncServiceClosure?(syncService) } + //MARK: - clearUserStatus + + open var clearUserStatusThrowableError: Error? + private let clearUserStatusCallsCountLock = NSLock() + private var clearUserStatusUnderlyingCallsCount = 0 + open var clearUserStatusCallsCount: Int { + get { clearUserStatusCallsCountLock.withLock { clearUserStatusUnderlyingCallsCount } } + set { clearUserStatusCallsCountLock.withLock { clearUserStatusUnderlyingCallsCount = newValue } } + } + open var clearUserStatusCalled: Bool { + return clearUserStatusCallsCount > 0 + } + open var clearUserStatusClosure: (() async throws -> Void)? + + open override func clearUserStatus() async throws { + if let error = clearUserStatusThrowableError { + throw error + } + clearUserStatusCallsCountLock.withLock { clearUserStatusUnderlyingCallsCount += 1 } + try await clearUserStatusClosure?() + } + //MARK: - contentScanner private let contentScannerCallsCountLock = NSLock() @@ -3245,6 +3267,42 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable { try await setPusherIdentifiersKindAppDisplayNameDeviceDisplayNameProfileTagLangAppendClosure?(identifiers, kind, appDisplayName, deviceDisplayName, profileTag, lang, append) } + //MARK: - setUserStatus + + open var setUserStatusStatusThrowableError: Error? + private let setUserStatusStatusCallsCountLock = NSLock() + private var setUserStatusStatusUnderlyingCallsCount = 0 + open var setUserStatusStatusCallsCount: Int { + get { setUserStatusStatusCallsCountLock.withLock { setUserStatusStatusUnderlyingCallsCount } } + set { setUserStatusStatusCallsCountLock.withLock { setUserStatusStatusUnderlyingCallsCount = newValue } } + } + open var setUserStatusStatusCalled: Bool { + return setUserStatusStatusCallsCount > 0 + } + private let setUserStatusStatusReceivedStatusLock = NSLock() + private var setUserStatusStatusUnderlyingReceivedStatus: UserStatus? + open var setUserStatusStatusReceivedStatus: UserStatus? { + get { setUserStatusStatusReceivedStatusLock.withLock { setUserStatusStatusUnderlyingReceivedStatus } } + set { setUserStatusStatusReceivedStatusLock.withLock { setUserStatusStatusUnderlyingReceivedStatus = newValue } } + } + private let setUserStatusStatusReceivedInvocationsLock = NSLock() + private var setUserStatusStatusUnderlyingReceivedInvocations: [UserStatus] = [] + open var setUserStatusStatusReceivedInvocations: [UserStatus] { + get { setUserStatusStatusReceivedInvocationsLock.withLock { setUserStatusStatusUnderlyingReceivedInvocations } } + set { setUserStatusStatusReceivedInvocationsLock.withLock { setUserStatusStatusUnderlyingReceivedInvocations = newValue } } + } + open var setUserStatusStatusClosure: ((UserStatus) async throws -> Void)? + + open override func setUserStatus(status: UserStatus) async throws { + if let error = setUserStatusStatusThrowableError { + throw error + } + setUserStatusStatusCallsCountLock.withLock { setUserStatusStatusUnderlyingCallsCount += 1 } + setUserStatusStatusReceivedStatus = status + setUserStatusStatusReceivedInvocationsLock.withLock { setUserStatusStatusUnderlyingReceivedInvocations.append(status) } + try await setUserStatusStatusClosure?(status) + } + //MARK: - setUtdDelegate open var setUtdDelegateUtdDelegateThrowableError: Error? @@ -16313,6 +16371,35 @@ open class SyncServiceBuilderSDKMock: MatrixRustSDK.SyncServiceBuilder, @uncheck } } + //MARK: - withProfilesExtension + + private let withProfilesExtensionCallsCountLock = NSLock() + private var withProfilesExtensionUnderlyingCallsCount = 0 + open var withProfilesExtensionCallsCount: Int { + get { withProfilesExtensionCallsCountLock.withLock { withProfilesExtensionUnderlyingCallsCount } } + set { withProfilesExtensionCallsCountLock.withLock { withProfilesExtensionUnderlyingCallsCount = newValue } } + } + open var withProfilesExtensionCalled: Bool { + return withProfilesExtensionCallsCount > 0 + } + + private let withProfilesExtensionReturnValueLock = NSLock() + open var withProfilesExtensionUnderlyingReturnValue: SyncServiceBuilder! + open var withProfilesExtensionReturnValue: SyncServiceBuilder! { + get { withProfilesExtensionReturnValueLock.withLock { withProfilesExtensionUnderlyingReturnValue } } + set { withProfilesExtensionReturnValueLock.withLock { withProfilesExtensionUnderlyingReturnValue = newValue } } + } + open var withProfilesExtensionClosure: (() -> SyncServiceBuilder)? + + open override func withProfilesExtension() -> SyncServiceBuilder { + withProfilesExtensionCallsCountLock.withLock { withProfilesExtensionUnderlyingCallsCount += 1 } + if let withProfilesExtensionClosure = withProfilesExtensionClosure { + return withProfilesExtensionClosure() + } else { + return withProfilesExtensionReturnValue + } + } + //MARK: - withRoomListConnectionId private let withRoomListConnectionIdConnectionIdCallsCountLock = NSLock() diff --git a/UnitTests/Sources/RoomEventStringBuilderTests.swift b/UnitTests/Sources/RoomEventStringBuilderTests.swift index 3368bc6e7..52b78f1a1 100644 --- a/UnitTests/Sources/RoomEventStringBuilderTests.swift +++ b/UnitTests/Sources/RoomEventStringBuilderTests.swift @@ -74,7 +74,11 @@ struct RoomEventStringBuilderTests { return .init(item: .init(configuration: .init(eventID: "1234", sender: senderID, - senderProfile: .ready(displayName: senderDisplayName, displayNameAmbiguous: senderDisplayNameAmbiguous, avatarUrl: nil), + senderProfile: .ready(displayName: senderDisplayName, + displayNameAmbiguous: senderDisplayNameAmbiguous, + avatarUrl: nil, + status: nil, + call: nil), isOwn: senderID == ownUserID, content: .msgLike(content: .init(kind: .message(content: .init(msgType: content, body: message, @@ -101,7 +105,11 @@ struct RoomEventStringBuilderTests { question: String = "Which is better?") -> EventTimelineItemProxy { .init(item: .init(configuration: .init(eventID: "1234", sender: senderID, - senderProfile: .ready(displayName: senderDisplayName, displayNameAmbiguous: senderDisplayNameAmbiguous, avatarUrl: nil), + senderProfile: .ready(displayName: senderDisplayName, + displayNameAmbiguous: senderDisplayNameAmbiguous, + avatarUrl: nil, + status: nil, + call: nil), isOwn: senderID == ownUserID, content: .msgLike(content: .init(kind: .poll(question: question, kind: .disclosed, diff --git a/project.yml b/project.yml index 1473381fb..62d44c09e 100644 --- a/project.yml +++ b/project.yml @@ -74,7 +74,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/element-hq/matrix-rust-components-swift - exactVersion: 26.07.08 + exactVersion: 26.07.14 # path: ../matrix-rust-sdk Compound: path: compound-ios