diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 67bd0831f0..56e4832517 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -7806,7 +7806,7 @@ repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = 1.0.57; + version = 1.0.58; }; }; 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index efa35cd9e8..0c07855fa0 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -149,8 +149,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/element-hq/matrix-rust-components-swift", "state" : { - "revision" : "5f01589d44aa7045dc1ad87f2583f6083295d3eb", - "version" : "1.0.57" + "revision" : "753c5381ce88b3549cbd8ed9b839109ff143ecdd", + "version" : "1.0.58" } }, { diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index fb48a3cd71..1c10cdbc56 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -933,7 +933,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { MXLog.debug("Selected \(emoji) for \(itemID)") navigationStackCoordinator.setSheetCoordinator(nil) Task { - await self.timelineController?.toggleReaction(emoji, to: itemID) + guard case let .event(_, eventOrTransactionID) = itemID else { + fatalError() + } + + await self.timelineController?.toggleReaction(emoji, to: eventOrTransactionID) } case .dismiss: navigationStackCoordinator.setSheetCoordinator(nil) diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index e3c0bace6a..1b472cd45a 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -14057,8 +14057,8 @@ class TimelineProxyMock: TimelineProxyProtocol { var redactReasonCalled: Bool { return redactReasonCallsCount > 0 } - var redactReasonReceivedArguments: (timelineItemID: TimelineItemIdentifier, reason: String?)? - var redactReasonReceivedInvocations: [(timelineItemID: TimelineItemIdentifier, reason: String?)] = [] + var redactReasonReceivedArguments: (eventOrTransactionID: EventOrTransactionId, reason: String?)? + var redactReasonReceivedInvocations: [(eventOrTransactionID: EventOrTransactionId, reason: String?)] = [] var redactReasonUnderlyingReturnValue: Result! var redactReasonReturnValue: Result! { @@ -14084,16 +14084,16 @@ class TimelineProxyMock: TimelineProxyProtocol { } } } - var redactReasonClosure: ((TimelineItemIdentifier, String?) async -> Result)? + var redactReasonClosure: ((EventOrTransactionId, String?) async -> Result)? - func redact(_ timelineItemID: TimelineItemIdentifier, reason: String?) async -> Result { + func redact(_ eventOrTransactionID: EventOrTransactionId, reason: String?) async -> Result { redactReasonCallsCount += 1 - redactReasonReceivedArguments = (timelineItemID: timelineItemID, reason: reason) + redactReasonReceivedArguments = (eventOrTransactionID: eventOrTransactionID, reason: reason) DispatchQueue.main.async { - self.redactReasonReceivedInvocations.append((timelineItemID: timelineItemID, reason: reason)) + self.redactReasonReceivedInvocations.append((eventOrTransactionID: eventOrTransactionID, reason: reason)) } if let redactReasonClosure = redactReasonClosure { - return await redactReasonClosure(timelineItemID, reason) + return await redactReasonClosure(eventOrTransactionID, reason) } else { return redactReasonReturnValue } @@ -14867,8 +14867,8 @@ class TimelineProxyMock: TimelineProxyProtocol { var toggleReactionToCalled: Bool { return toggleReactionToCallsCount > 0 } - var toggleReactionToReceivedArguments: (reaction: String, itemID: TimelineItemIdentifier)? - var toggleReactionToReceivedInvocations: [(reaction: String, itemID: TimelineItemIdentifier)] = [] + var toggleReactionToReceivedArguments: (reaction: String, eventID: EventOrTransactionId)? + var toggleReactionToReceivedInvocations: [(reaction: String, eventID: EventOrTransactionId)] = [] var toggleReactionToUnderlyingReturnValue: Result! var toggleReactionToReturnValue: Result! { @@ -14894,16 +14894,16 @@ class TimelineProxyMock: TimelineProxyProtocol { } } } - var toggleReactionToClosure: ((String, TimelineItemIdentifier) async -> Result)? + var toggleReactionToClosure: ((String, EventOrTransactionId) async -> Result)? - func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async -> Result { + func toggleReaction(_ reaction: String, to eventID: EventOrTransactionId) async -> Result { toggleReactionToCallsCount += 1 - toggleReactionToReceivedArguments = (reaction: reaction, itemID: itemID) + toggleReactionToReceivedArguments = (reaction: reaction, eventID: eventID) DispatchQueue.main.async { - self.toggleReactionToReceivedInvocations.append((reaction: reaction, itemID: itemID)) + self.toggleReactionToReceivedInvocations.append((reaction: reaction, eventID: eventID)) } if let toggleReactionToClosure = toggleReactionToClosure { - return await toggleReactionToClosure(reaction, itemID) + return await toggleReactionToClosure(reaction, eventID) } else { return toggleReactionToReturnValue } diff --git a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift index e4548ff0f1..52c51b578b 100644 --- a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift @@ -15,17 +15,17 @@ open class ClientSDKMock: MatrixRustSDK.Client { fileprivate var pointer: UnsafeMutableRawPointer! - //MARK: - abortOidcLogin + //MARK: - abortOidcAuth - var abortOidcLoginAuthorizationDataUnderlyingCallsCount = 0 - open var abortOidcLoginAuthorizationDataCallsCount: Int { + var abortOidcAuthAuthorizationDataUnderlyingCallsCount = 0 + open var abortOidcAuthAuthorizationDataCallsCount: Int { get { if Thread.isMainThread { - return abortOidcLoginAuthorizationDataUnderlyingCallsCount + return abortOidcAuthAuthorizationDataUnderlyingCallsCount } else { var returnValue: Int? = nil DispatchQueue.main.sync { - returnValue = abortOidcLoginAuthorizationDataUnderlyingCallsCount + returnValue = abortOidcAuthAuthorizationDataUnderlyingCallsCount } return returnValue! @@ -33,28 +33,28 @@ open class ClientSDKMock: MatrixRustSDK.Client { } set { if Thread.isMainThread { - abortOidcLoginAuthorizationDataUnderlyingCallsCount = newValue + abortOidcAuthAuthorizationDataUnderlyingCallsCount = newValue } else { DispatchQueue.main.sync { - abortOidcLoginAuthorizationDataUnderlyingCallsCount = newValue + abortOidcAuthAuthorizationDataUnderlyingCallsCount = newValue } } } } - open var abortOidcLoginAuthorizationDataCalled: Bool { - return abortOidcLoginAuthorizationDataCallsCount > 0 + open var abortOidcAuthAuthorizationDataCalled: Bool { + return abortOidcAuthAuthorizationDataCallsCount > 0 } - open var abortOidcLoginAuthorizationDataReceivedAuthorizationData: OidcAuthorizationData? - open var abortOidcLoginAuthorizationDataReceivedInvocations: [OidcAuthorizationData] = [] - open var abortOidcLoginAuthorizationDataClosure: ((OidcAuthorizationData) async -> Void)? + open var abortOidcAuthAuthorizationDataReceivedAuthorizationData: OidcAuthorizationData? + open var abortOidcAuthAuthorizationDataReceivedInvocations: [OidcAuthorizationData] = [] + open var abortOidcAuthAuthorizationDataClosure: ((OidcAuthorizationData) async -> Void)? - open override func abortOidcLogin(authorizationData: OidcAuthorizationData) async { - abortOidcLoginAuthorizationDataCallsCount += 1 - abortOidcLoginAuthorizationDataReceivedAuthorizationData = authorizationData + open override func abortOidcAuth(authorizationData: OidcAuthorizationData) async { + abortOidcAuthAuthorizationDataCallsCount += 1 + abortOidcAuthAuthorizationDataReceivedAuthorizationData = authorizationData DispatchQueue.main.async { - self.abortOidcLoginAuthorizationDataReceivedInvocations.append(authorizationData) + self.abortOidcAuthAuthorizationDataReceivedInvocations.append(authorizationData) } - await abortOidcLoginAuthorizationDataClosure?(authorizationData) + await abortOidcAuthAuthorizationDataClosure?(authorizationData) } //MARK: - accountData @@ -3872,18 +3872,18 @@ open class ClientSDKMock: MatrixRustSDK.Client { } } - //MARK: - urlForOidcLogin + //MARK: - urlForOidc - open var urlForOidcLoginOidcConfigurationThrowableError: Error? - var urlForOidcLoginOidcConfigurationUnderlyingCallsCount = 0 - open var urlForOidcLoginOidcConfigurationCallsCount: Int { + open var urlForOidcOidcConfigurationPromptThrowableError: Error? + var urlForOidcOidcConfigurationPromptUnderlyingCallsCount = 0 + open var urlForOidcOidcConfigurationPromptCallsCount: Int { get { if Thread.isMainThread { - return urlForOidcLoginOidcConfigurationUnderlyingCallsCount + return urlForOidcOidcConfigurationPromptUnderlyingCallsCount } else { var returnValue: Int? = nil DispatchQueue.main.sync { - returnValue = urlForOidcLoginOidcConfigurationUnderlyingCallsCount + returnValue = urlForOidcOidcConfigurationPromptUnderlyingCallsCount } return returnValue! @@ -3891,29 +3891,29 @@ open class ClientSDKMock: MatrixRustSDK.Client { } set { if Thread.isMainThread { - urlForOidcLoginOidcConfigurationUnderlyingCallsCount = newValue + urlForOidcOidcConfigurationPromptUnderlyingCallsCount = newValue } else { DispatchQueue.main.sync { - urlForOidcLoginOidcConfigurationUnderlyingCallsCount = newValue + urlForOidcOidcConfigurationPromptUnderlyingCallsCount = newValue } } } } - open var urlForOidcLoginOidcConfigurationCalled: Bool { - return urlForOidcLoginOidcConfigurationCallsCount > 0 + open var urlForOidcOidcConfigurationPromptCalled: Bool { + return urlForOidcOidcConfigurationPromptCallsCount > 0 } - open var urlForOidcLoginOidcConfigurationReceivedOidcConfiguration: OidcConfiguration? - open var urlForOidcLoginOidcConfigurationReceivedInvocations: [OidcConfiguration] = [] + open var urlForOidcOidcConfigurationPromptReceivedArguments: (oidcConfiguration: OidcConfiguration, prompt: OidcPrompt)? + open var urlForOidcOidcConfigurationPromptReceivedInvocations: [(oidcConfiguration: OidcConfiguration, prompt: OidcPrompt)] = [] - var urlForOidcLoginOidcConfigurationUnderlyingReturnValue: OidcAuthorizationData! - open var urlForOidcLoginOidcConfigurationReturnValue: OidcAuthorizationData! { + var urlForOidcOidcConfigurationPromptUnderlyingReturnValue: OidcAuthorizationData! + open var urlForOidcOidcConfigurationPromptReturnValue: OidcAuthorizationData! { get { if Thread.isMainThread { - return urlForOidcLoginOidcConfigurationUnderlyingReturnValue + return urlForOidcOidcConfigurationPromptUnderlyingReturnValue } else { var returnValue: OidcAuthorizationData? = nil DispatchQueue.main.sync { - returnValue = urlForOidcLoginOidcConfigurationUnderlyingReturnValue + returnValue = urlForOidcOidcConfigurationPromptUnderlyingReturnValue } return returnValue! @@ -3921,29 +3921,29 @@ open class ClientSDKMock: MatrixRustSDK.Client { } set { if Thread.isMainThread { - urlForOidcLoginOidcConfigurationUnderlyingReturnValue = newValue + urlForOidcOidcConfigurationPromptUnderlyingReturnValue = newValue } else { DispatchQueue.main.sync { - urlForOidcLoginOidcConfigurationUnderlyingReturnValue = newValue + urlForOidcOidcConfigurationPromptUnderlyingReturnValue = newValue } } } } - open var urlForOidcLoginOidcConfigurationClosure: ((OidcConfiguration) async throws -> OidcAuthorizationData)? + open var urlForOidcOidcConfigurationPromptClosure: ((OidcConfiguration, OidcPrompt) async throws -> OidcAuthorizationData)? - open override func urlForOidcLogin(oidcConfiguration: OidcConfiguration) async throws -> OidcAuthorizationData { - if let error = urlForOidcLoginOidcConfigurationThrowableError { + open override func urlForOidc(oidcConfiguration: OidcConfiguration, prompt: OidcPrompt) async throws -> OidcAuthorizationData { + if let error = urlForOidcOidcConfigurationPromptThrowableError { throw error } - urlForOidcLoginOidcConfigurationCallsCount += 1 - urlForOidcLoginOidcConfigurationReceivedOidcConfiguration = oidcConfiguration + urlForOidcOidcConfigurationPromptCallsCount += 1 + urlForOidcOidcConfigurationPromptReceivedArguments = (oidcConfiguration: oidcConfiguration, prompt: prompt) DispatchQueue.main.async { - self.urlForOidcLoginOidcConfigurationReceivedInvocations.append(oidcConfiguration) + self.urlForOidcOidcConfigurationPromptReceivedInvocations.append((oidcConfiguration: oidcConfiguration, prompt: prompt)) } - if let urlForOidcLoginOidcConfigurationClosure = urlForOidcLoginOidcConfigurationClosure { - return try await urlForOidcLoginOidcConfigurationClosure(oidcConfiguration) + if let urlForOidcOidcConfigurationPromptClosure = urlForOidcOidcConfigurationPromptClosure { + return try await urlForOidcOidcConfigurationPromptClosure(oidcConfiguration, prompt) } else { - return urlForOidcLoginOidcConfigurationReturnValue + return urlForOidcOidcConfigurationPromptReturnValue } } @@ -19484,16 +19484,16 @@ open class TimelineSDKMock: MatrixRustSDK.Timeline { //MARK: - toggleReaction - open var toggleReactionUniqueIdKeyThrowableError: Error? - var toggleReactionUniqueIdKeyUnderlyingCallsCount = 0 - open var toggleReactionUniqueIdKeyCallsCount: Int { + open var toggleReactionItemIdKeyThrowableError: Error? + var toggleReactionItemIdKeyUnderlyingCallsCount = 0 + open var toggleReactionItemIdKeyCallsCount: Int { get { if Thread.isMainThread { - return toggleReactionUniqueIdKeyUnderlyingCallsCount + return toggleReactionItemIdKeyUnderlyingCallsCount } else { var returnValue: Int? = nil DispatchQueue.main.sync { - returnValue = toggleReactionUniqueIdKeyUnderlyingCallsCount + returnValue = toggleReactionItemIdKeyUnderlyingCallsCount } return returnValue! @@ -19501,31 +19501,31 @@ open class TimelineSDKMock: MatrixRustSDK.Timeline { } set { if Thread.isMainThread { - toggleReactionUniqueIdKeyUnderlyingCallsCount = newValue + toggleReactionItemIdKeyUnderlyingCallsCount = newValue } else { DispatchQueue.main.sync { - toggleReactionUniqueIdKeyUnderlyingCallsCount = newValue + toggleReactionItemIdKeyUnderlyingCallsCount = newValue } } } } - open var toggleReactionUniqueIdKeyCalled: Bool { - return toggleReactionUniqueIdKeyCallsCount > 0 + open var toggleReactionItemIdKeyCalled: Bool { + return toggleReactionItemIdKeyCallsCount > 0 } - open var toggleReactionUniqueIdKeyReceivedArguments: (uniqueId: String, key: String)? - open var toggleReactionUniqueIdKeyReceivedInvocations: [(uniqueId: String, key: String)] = [] - open var toggleReactionUniqueIdKeyClosure: ((String, String) async throws -> Void)? + open var toggleReactionItemIdKeyReceivedArguments: (itemId: EventOrTransactionId, key: String)? + open var toggleReactionItemIdKeyReceivedInvocations: [(itemId: EventOrTransactionId, key: String)] = [] + open var toggleReactionItemIdKeyClosure: ((EventOrTransactionId, String) async throws -> Void)? - open override func toggleReaction(uniqueId: String, key: String) async throws { - if let error = toggleReactionUniqueIdKeyThrowableError { + open override func toggleReaction(itemId: EventOrTransactionId, key: String) async throws { + if let error = toggleReactionItemIdKeyThrowableError { throw error } - toggleReactionUniqueIdKeyCallsCount += 1 - toggleReactionUniqueIdKeyReceivedArguments = (uniqueId: uniqueId, key: key) + toggleReactionItemIdKeyCallsCount += 1 + toggleReactionItemIdKeyReceivedArguments = (itemId: itemId, key: key) DispatchQueue.main.async { - self.toggleReactionUniqueIdKeyReceivedInvocations.append((uniqueId: uniqueId, key: key)) + self.toggleReactionItemIdKeyReceivedInvocations.append((itemId: itemId, key: key)) } - try await toggleReactionUniqueIdKeyClosure?(uniqueId, key) + try await toggleReactionItemIdKeyClosure?(itemId, key) } //MARK: - unpinEvent @@ -20724,13 +20724,13 @@ open class TimelineItemSDKMock: MatrixRustSDK.TimelineItem { return uniqueIdCallsCount > 0 } - var uniqueIdUnderlyingReturnValue: String! - open var uniqueIdReturnValue: String! { + var uniqueIdUnderlyingReturnValue: TimelineUniqueId! + open var uniqueIdReturnValue: TimelineUniqueId! { get { if Thread.isMainThread { return uniqueIdUnderlyingReturnValue } else { - var returnValue: String? = nil + var returnValue: TimelineUniqueId? = nil DispatchQueue.main.sync { returnValue = uniqueIdUnderlyingReturnValue } @@ -20748,9 +20748,9 @@ open class TimelineItemSDKMock: MatrixRustSDK.TimelineItem { } } } - open var uniqueIdClosure: (() -> String)? + open var uniqueIdClosure: (() -> TimelineUniqueId)? - open override func uniqueId() -> String { + open override func uniqueId() -> TimelineUniqueId { uniqueIdCallsCount += 1 if let uniqueIdClosure = uniqueIdClosure { return uniqueIdClosure() diff --git a/ElementX/Sources/Mocks/RoomTimelineProviderMock.swift b/ElementX/Sources/Mocks/RoomTimelineProviderMock.swift index 12a1e4806c..53e9d73c99 100644 --- a/ElementX/Sources/Mocks/RoomTimelineProviderMock.swift +++ b/ElementX/Sources/Mocks/RoomTimelineProviderMock.swift @@ -38,7 +38,7 @@ class AutoUpdatingRoomTimelineProviderMock: RoomTimelineProvider { let timelineItem = TimelineItemSDKMock() timelineItem.asEventReturnValue = EventTimelineItem.mockMessage - timelineItem.uniqueIdReturnValue = UUID().uuidString + timelineItem.uniqueIdReturnValue = .init(id: UUID().uuidString) diff.appendReturnValue = [timelineItem] diff --git a/ElementX/Sources/Mocks/SDK/ClientSDKMock.swift b/ElementX/Sources/Mocks/SDK/ClientSDKMock.swift index 61738a095f..29e80bd3dc 100644 --- a/ElementX/Sources/Mocks/SDK/ClientSDKMock.swift +++ b/ElementX/Sources/Mocks/SDK/ClientSDKMock.swift @@ -42,7 +42,7 @@ extension ClientSDKMock { userIdServerNameThrowableError = MockError.generic serverReturnValue = "https://\(configuration.serverAddress)" getUrlUrlReturnValue = configuration.elementWellKnown - urlForOidcLoginOidcConfigurationReturnValue = OidcAuthorizationDataSDKMock(configuration: configuration) + urlForOidcOidcConfigurationPromptReturnValue = OidcAuthorizationDataSDKMock(configuration: configuration) loginUsernamePasswordInitialDeviceNameDeviceIdClosure = { username, password, _, _ in guard username == configuration.validCredentials.username, password == configuration.validCredentials.password else { diff --git a/ElementX/Sources/Screens/Timeline/TimelineInteractionHandler.swift b/ElementX/Sources/Screens/Timeline/TimelineInteractionHandler.swift index 3bab9b8db4..281183664f 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineInteractionHandler.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineInteractionHandler.swift @@ -132,8 +132,12 @@ class TimelineInteractionHandler { UIPasteboard.general.url = permalinkURL } case .redact: + guard case let .event(_, eventOrTransactionID) = itemID else { + fatalError() + } + Task { - await timelineController.redact(itemID) + await timelineController.redact(eventOrTransactionID) } case .reply: guard let eventID = eventTimelineItem.id.eventID else { @@ -159,7 +163,13 @@ class TimelineInteractionHandler { case .react: displayEmojiPicker(for: itemID) case .toggleReaction(let key): - Task { await timelineController.toggleReaction(key, to: itemID) } + Task { + guard case let .event(_, eventOrTransactionID) = itemID else { + fatalError() + } + + await timelineController.toggleReaction(key, to: eventOrTransactionID) + } case .endPoll(let pollStartID): endPoll(pollStartID: pollStartID) case .pin: diff --git a/ElementX/Sources/Screens/Timeline/TimelineModels.swift b/ElementX/Sources/Screens/Timeline/TimelineModels.swift index 6bfcc9b9ca..44a7ed0834 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineModels.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineModels.swift @@ -6,6 +6,7 @@ // import Combine +import MatrixRustSDK import OrderedCollections import SwiftUI @@ -202,9 +203,9 @@ struct TimelineState { // These can be removed when we have full swiftUI and moved as @State values in the view var scrollToBottomPublisher = PassthroughSubject() - var itemsDictionary = OrderedDictionary() + var itemsDictionary = OrderedDictionary() - var uniqueIDs: [String] { + var uniqueIDs: [TimelineUniqueId] { itemsDictionary.keys.elements } diff --git a/ElementX/Sources/Screens/Timeline/TimelineTableViewController.swift b/ElementX/Sources/Screens/Timeline/TimelineTableViewController.swift index 8876749e8f..84fde96d3b 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineTableViewController.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineTableViewController.swift @@ -7,6 +7,7 @@ import Combine import Compound +import MatrixRustSDK import SwiftUI import OrderedCollections @@ -47,7 +48,7 @@ class TimelineTableViewController: UIViewController { private let coordinator: TimelineView.Coordinator private let tableView = UITableView(frame: .zero, style: .plain) - var timelineItemsDictionary = OrderedDictionary() { + var timelineItemsDictionary = OrderedDictionary() { didSet { guard canApplySnapshot else { hasPendingItems = true @@ -145,12 +146,12 @@ class TimelineTableViewController: UIViewController { @Binding private var isScrolledToBottom: Bool - private var timelineItemsIDs: [String] { + private var timelineItemsIDs: [TimelineUniqueId] { timelineItemsDictionary.keys.elements.reversed() } /// The table's diffable data source. - private var dataSource: UITableViewDiffableDataSource? + private var dataSource: UITableViewDiffableDataSource? private var cancellables = Set() /// A publisher used to throttle back pagination requests. @@ -246,7 +247,7 @@ class TimelineTableViewController: UIViewController { private func configureDataSource() { dataSource = .init(tableView: tableView) { [weak self] tableView, indexPath, id in switch id { - case TimelineTypingIndicatorCell.reuseIdentifier: + case TimelineUniqueId(id: TimelineTypingIndicatorCell.reuseIdentifier): let cell = tableView.dequeueReusableCell(withIdentifier: TimelineTypingIndicatorCell.reuseIdentifier, for: indexPath) guard let self else { return cell @@ -312,12 +313,12 @@ class TimelineTableViewController: UIViewController { private func applySnapshot() { guard let dataSource else { return } - var snapshot = NSDiffableDataSourceSnapshot() + var snapshot = NSDiffableDataSourceSnapshot() // We don't want to display the typing notification in this timeline if !coordinator.context.viewState.isPinnedEventsTimeline { snapshot.appendSections([.typingIndicator]) - snapshot.appendItems([TimelineTypingIndicatorCell.reuseIdentifier]) + snapshot.appendItems([TimelineUniqueId(id: TimelineTypingIndicatorCell.reuseIdentifier)]) } snapshot.appendSections([.main]) snapshot.appendItems(timelineItemsIDs) @@ -516,7 +517,7 @@ extension TimelineTableViewController { } /// Returns the frame of the cell for a particular timeline item. - private func cellFrame(for uniqueID: String) -> CGRect? { + private func cellFrame(for uniqueID: TimelineUniqueId) -> CGRect? { guard let timelineCell = tableView.visibleCells.first(where: { ($0 as? TimelineItemCell)?.item?.identifier.uniqueID == uniqueID }) else { return nil } @@ -536,13 +537,13 @@ extension TimelineTableViewController { } } -private extension NSDiffableDataSourceSnapshot { +private extension NSDiffableDataSourceSnapshot { var numberOfMainItems: Int { guard sectionIdentifiers.contains(.main) else { return 0 } return numberOfItems(inSection: .main) } - var mainItemIdentifiers: [String] { + var mainItemIdentifiers: [TimelineUniqueId] { guard sectionIdentifiers.contains(.main) else { return [] } return itemIdentifiers(inSection: .main) } diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index bc83d1d71c..80c2460361 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -131,8 +131,12 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { Task { await handleItemTapped(with: id) } case .itemSendInfoTapped(let itemID): handleItemSendInfoTapped(itemID: itemID) - case .toggleReaction(let emoji, let itemId): - Task { await timelineController.toggleReaction(emoji, to: itemId) } + case .toggleReaction(let emoji, let itemID): + guard case let .event(_, eventOrTransactionID) = itemID else { + fatalError() + } + + Task { await timelineController.toggleReaction(emoji, to: eventOrTransactionID) } case .sendReadReceiptIfNeeded(let lastVisibleItemID): Task { await sendReadReceiptIfNeeded(for: lastVisibleItemID) } case .paginateBackwards: @@ -639,7 +643,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { // MARK: - Timeline Item Building private func buildTimelineViews(timelineItems: [RoomTimelineItemProtocol], isSwitchingTimelines: Bool = false) { - var timelineItemsDictionary = OrderedDictionary() + var timelineItemsDictionary = OrderedDictionary() timelineItems.filter { $0 is RedactedRoomTimelineItem }.forEach { timelineItem in // Stops the audio player when a voice message is redacted. diff --git a/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift b/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift index 4b6eaf2e46..63e2304ba2 100644 --- a/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift +++ b/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift @@ -623,7 +623,7 @@ private struct MockTimelineContent: View { } func makeItemIdentifier() -> TimelineItemIdentifier { - isPinned ? .event(uniqueID: "", eventOrTransactionID: .eventId(eventId: "pinned")) : .randomEvent + isPinned ? .event(uniqueID: .init(id: ""), eventOrTransactionID: .eventId(eventId: "pinned")) : .randomEvent } var replyDetails: TimelineItemReplyDetails? { diff --git a/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift b/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift index 820cdd6423..1cafaf023e 100644 --- a/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift +++ b/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift @@ -79,7 +79,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview { }() static let sendingLast: TextRoomTimelineItem = { - let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString + let id = viewModel.state.timelineViewState.uniqueIDs.last ?? .init(id: UUID().uuidString) var result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)), timestamp: "Now", isOutgoing: true, @@ -99,7 +99,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview { }() static let sentLast: TextRoomTimelineItem = { - let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString + let id = viewModel.state.timelineViewState.uniqueIDs.last ?? .init(id: UUID().uuidString) let result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)), timestamp: "Now", isOutgoing: true, diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/CollapsibleRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/CollapsibleRoomTimelineView.swift index 03c212504d..d7b85ce801 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/CollapsibleRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/CollapsibleRoomTimelineView.swift @@ -52,8 +52,8 @@ struct CollapsibleRoomTimelineView: View { struct CollapsibleRoomTimelineView_Previews: PreviewProvider, TestablePreview { static let item = CollapsibleTimelineItem(items: [ - SeparatorRoomTimelineItem(id: .virtual(uniqueID: "First separator"), text: "This is a separator"), - SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Second separator"), text: "This is another separator") + SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "First separator")), text: "This is a separator"), + SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Second separator")), text: "This is another separator") ]) static var previews: some View { diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ReadMarkerRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ReadMarkerRoomTimelineView.swift index 8bbfaf7870..4314885116 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ReadMarkerRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ReadMarkerRoomTimelineView.swift @@ -33,7 +33,7 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview { static var previews: some View { VStack(alignment: .leading, spacing: 0) { - RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: "Separator"), text: "Today")), groupStyle: .single)) + RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: .init(id: "Separator")), text: "Today")), groupStyle: .single)) RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent, timestamp: "", isOutgoing: true, @@ -45,7 +45,7 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview { ReadMarkerRoomTimelineView(timelineItem: item) - RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: "Separator"), text: "Today")), groupStyle: .single)) + RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: .init(id: "Separator")), text: "Today")), groupStyle: .single)) RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent, timestamp: "", isOutgoing: false, diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/SeparatorRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/SeparatorRoomTimelineView.swift index 3c6be1189c..88633b6904 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/SeparatorRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/SeparatorRoomTimelineView.swift @@ -23,7 +23,7 @@ struct SeparatorRoomTimelineView: View { struct SeparatorRoomTimelineView_Previews: PreviewProvider, TestablePreview { static var previews: some View { - let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Separator"), + let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Separator")), text: "This is a separator") SeparatorRoomTimelineView(timelineItem: item) } diff --git a/ElementX/Sources/Services/Authentication/AuthenticationService.swift b/ElementX/Sources/Services/Authentication/AuthenticationService.swift index 092a097024..4c3307377a 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationService.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationService.swift @@ -91,7 +91,7 @@ class AuthenticationService: AuthenticationServiceProtocol { func urlForOIDCLogin() async -> Result { guard let client else { return .failure(.oidcError(.urlFailure)) } do { - let oidcData = try await client.urlForOidcLogin(oidcConfiguration: appSettings.oidcConfiguration.rustValue) + let oidcData = try await client.urlForOidc(oidcConfiguration: appSettings.oidcConfiguration.rustValue, prompt: .consent) return .success(OIDCAuthorizationDataProxy(underlyingData: oidcData)) } catch { MXLog.error("Failed to get URL for OIDC login: \(error)") @@ -102,7 +102,7 @@ class AuthenticationService: AuthenticationServiceProtocol { func abortOIDCLogin(data: OIDCAuthorizationDataProxy) async { guard let client else { return } MXLog.info("Aborting OIDC login.") - await client.abortOidcLogin(authorizationData: data.underlyingData) + await client.abortOidcAuth(authorizationData: data.underlyingData) } func loginWithOIDCCallback(_ callbackURL: URL, data: OIDCAuthorizationDataProxy) async -> Result { diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index 7c66bbc28a..b1b4c37192 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -246,7 +246,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { var lastMessageFormattedTimestamp: String? if let latestRoomMessage = roomDetails.latestEvent { - let lastMessage = EventTimelineItemProxy(item: latestRoomMessage, uniqueID: "0") + let lastMessage = EventTimelineItemProxy(item: latestRoomMessage, uniqueID: .init(id: "0")) lastMessageFormattedTimestamp = lastMessage.timestamp.formattedMinimal() attributedLastMessage = eventStringBuilder.buildAttributedString(for: lastMessage) } diff --git a/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift b/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift index dda6752769..cf77fa6da9 100644 --- a/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift +++ b/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift @@ -10,8 +10,8 @@ import Foundation enum RoomTimelineItemFixtures { /// The default timeline items used in Xcode previews etc. static var `default`: [RoomTimelineItemProtocol] = [ - SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Yesterday"), text: "Yesterday"), - TextRoomTimelineItem(id: .event(uniqueID: ".RoomTimelineItemFixtures.default.0", + SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Yesterday")), text: "Yesterday"), + TextRoomTimelineItem(id: .event(uniqueID: .init(id: ".RoomTimelineItemFixtures.default.0"), eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.0")), timestamp: "10:10 AM", isOutgoing: false, @@ -21,7 +21,7 @@ enum RoomTimelineItemFixtures { sender: .init(id: "", displayName: "Jacob"), content: .init(body: "That looks so good!"), properties: RoomTimelineItemProperties(isEdited: true)), - TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.1", + TextRoomTimelineItem(id: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.1"), eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.1")), timestamp: "10:11 AM", isOutgoing: false, @@ -33,7 +33,7 @@ enum RoomTimelineItemFixtures { properties: RoomTimelineItemProperties(reactions: [ AggregatedReaction(accountOwnerID: "me", key: "🙌", senders: [ReactionSender(id: "me", timestamp: Date())]) ])), - TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.2", + TextRoomTimelineItem(id: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.2"), eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.2")), timestamp: "10:11 AM", isOutgoing: false, @@ -52,8 +52,8 @@ enum RoomTimelineItemFixtures { ReactionSender(id: "jacob", timestamp: Date()) ]) ])), - SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Today"), text: "Today"), - TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.3", + SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Today")), text: "Today"), + TextRoomTimelineItem(id: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.3"), eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.3")), timestamp: "5 PM", isOutgoing: false, @@ -63,7 +63,7 @@ enum RoomTimelineItemFixtures { sender: .init(id: "", displayName: "Helena"), content: .init(body: "Wow, cool. Ok, lets go the usual place tomorrow?! Is that too soon? Here’s the menu, let me know what you want it’s on me!"), properties: RoomTimelineItemProperties(orderedReadReceipts: [ReadReceipt(userID: "alice", formattedTimestamp: nil)])), - TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.4", + TextRoomTimelineItem(id: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.4"), eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.4")), timestamp: "5 PM", isOutgoing: true, @@ -72,7 +72,7 @@ enum RoomTimelineItemFixtures { isThreaded: false, sender: .init(id: "", displayName: "Bob"), content: .init(body: "And John's speech was amazing!")), - TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.5", + TextRoomTimelineItem(id: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.5"), eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.5")), timestamp: "5 PM", isOutgoing: true, @@ -86,7 +86,7 @@ enum RoomTimelineItemFixtures { ReadReceipt(userID: "bob", formattedTimestamp: nil), ReadReceipt(userID: "charlie", formattedTimestamp: nil), ReadReceipt(userID: "dan", formattedTimestamp: nil)])), - TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.6", + TextRoomTimelineItem(id: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.6"), eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.6")), timestamp: "5 PM", isOutgoing: false, @@ -242,7 +242,7 @@ enum RoomTimelineItemFixtures { static var permalinkChunk: [RoomTimelineItemProtocol] { (1...20).map { index in - TextRoomTimelineItem(id: .event(uniqueID: "\(index)", eventOrTransactionID: .eventId(eventId: "$\(index)")), + TextRoomTimelineItem(id: .event(uniqueID: .init(id: "\(index)"), eventOrTransactionID: .eventId(eventId: "$\(index)")), text: "Message ID \(index)", senderDisplayName: index > 10 ? "Alice" : "Bob") } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineController.swift index 155989b151..c5d18c0729 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineController.swift @@ -84,7 +84,7 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol { inReplyToEventID: String?, intentionalMentions: IntentionalMentions) async { } - func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async { } + func toggleReaction(_ reaction: String, to eventID: EventOrTransactionId) async { } func edit(_ eventOrTransactionID: EventOrTransactionId, useTimeline: Bool, @@ -92,7 +92,7 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol { html: String?, intentionalMentions: IntentionalMentions) async { } - func redact(_ itemID: TimelineItemIdentifier) async { } + func redact(_ eventOrTransactionID: EventOrTransactionId) async { } func pin(eventID: String) async { } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift index 0ef0dbd1d6..f9738a1735 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift @@ -158,10 +158,10 @@ class RoomTimelineController: RoomTimelineControllerProtocol { } } - func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async { - MXLog.info("Toggle reaction in \(roomID)") + func toggleReaction(_ reaction: String, to eventOrTransactionID: EventOrTransactionId) async { + MXLog.info("Toggle reaction \(reaction) to \(eventOrTransactionID)") - switch await activeTimeline.toggleReaction(reaction, to: itemID) { + switch await activeTimeline.toggleReaction(reaction, to: eventOrTransactionID) { case .success: MXLog.info("Finished toggling reaction") case .failure(let error): @@ -203,10 +203,10 @@ class RoomTimelineController: RoomTimelineControllerProtocol { } } - func redact(_ timelineItemID: TimelineItemIdentifier) async { + func redact(_ eventOrTransactionID: EventOrTransactionId) async { MXLog.info("Send redaction in \(roomID)") - switch await activeTimeline.redact(timelineItemID, reason: nil) { + switch await activeTimeline.redact(eventOrTransactionID, reason: nil) { case .success: MXLog.info("Finished redacting message") case .failure(let error): diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift index be7c635585..4b47bacf44 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift @@ -57,9 +57,9 @@ protocol RoomTimelineControllerProtocol { html: String?, intentionalMentions: IntentionalMentions) async - func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async + func toggleReaction(_ reaction: String, to eventOrTransactionID: EventOrTransactionId) async - func redact(_ itemID: TimelineItemIdentifier) async + func redact(_ eventOrTransactionID: EventOrTransactionId) async func pin(eventID: String) async diff --git a/ElementX/Sources/Services/Timeline/TimelineItemIdentifier.swift b/ElementX/Sources/Services/Timeline/TimelineItemIdentifier.swift index 1770dbb493..a6efccb371 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItemIdentifier.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItemIdentifier.swift @@ -14,10 +14,10 @@ import MatrixRustSDK /// - eventOrTransactionID: Contains the 2 possible identifiers of an event, either it has a remote event id or /// a local transaction id, never both or none. enum TimelineItemIdentifier: Hashable { - case event(uniqueID: String, eventOrTransactionID: EventOrTransactionId) - case virtual(uniqueID: String) + case event(uniqueID: TimelineUniqueId, eventOrTransactionID: EventOrTransactionId) + case virtual(uniqueID: TimelineUniqueId) - var uniqueID: String { + var uniqueID: TimelineUniqueId { switch self { case .event(let uniqueID, _): return uniqueID @@ -57,10 +57,10 @@ enum TimelineItemIdentifier: Hashable { extension TimelineItemIdentifier { static var randomEvent: Self { - .event(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: UUID().uuidString)) + .event(uniqueID: .init(id: UUID().uuidString), eventOrTransactionID: .eventId(eventId: UUID().uuidString)) } static var randomVirtual: Self { - .virtual(uniqueID: UUID().uuidString) + .virtual(uniqueID: .init(id: UUID().uuidString)) } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift b/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift index ef956e8068..bb939082f8 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift @@ -11,14 +11,14 @@ import MatrixRustSDK /// A light wrapper around timeline items returned from Rust. enum TimelineItemProxy { case event(EventTimelineItemProxy) - case virtual(MatrixRustSDK.VirtualTimelineItem, uniqueID: String) + case virtual(MatrixRustSDK.VirtualTimelineItem, uniqueID: TimelineUniqueId) case unknown(MatrixRustSDK.TimelineItem) init(item: MatrixRustSDK.TimelineItem) { if let eventItem = item.asEvent() { - self = .event(EventTimelineItemProxy(item: eventItem, uniqueID: String(item.uniqueId()))) + self = .event(EventTimelineItemProxy(item: eventItem, uniqueID: item.uniqueId())) } else if let virtualItem = item.asVirtual() { - self = .virtual(virtualItem, uniqueID: String(item.uniqueId())) + self = .virtual(virtualItem, uniqueID: item.uniqueId()) } else { self = .unknown(item) } @@ -71,7 +71,7 @@ class EventTimelineItemProxy { let item: MatrixRustSDK.EventTimelineItem let id: TimelineItemIdentifier - init(item: MatrixRustSDK.EventTimelineItem, uniqueID: String) { + init(item: MatrixRustSDK.EventTimelineItem, uniqueID: TimelineUniqueId) { self.item = item id = .event(uniqueID: uniqueID, eventOrTransactionID: item.eventOrTransactionId) diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/PaginationIndicatorRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/PaginationIndicatorRoomTimelineItem.swift index 319d024476..139a50eb3e 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/PaginationIndicatorRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/PaginationIndicatorRoomTimelineItem.swift @@ -22,6 +22,6 @@ struct PaginationIndicatorRoomTimelineItem: DecorationTimelineItemProtocol, Equa } init(position: Position) { - id = .virtual(uniqueID: position.id) + id = .virtual(uniqueID: .init(id: position.id)) } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/TimelineStartRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/TimelineStartRoomTimelineItem.swift index 33a601445f..44237552fe 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/TimelineStartRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/TimelineStartRoomTimelineItem.swift @@ -8,6 +8,6 @@ import Foundation struct TimelineStartRoomTimelineItem: DecorationTimelineItemProtocol, Equatable { - let id: TimelineItemIdentifier = .virtual(uniqueID: UUID().uuidString) + let id: TimelineItemIdentifier = .virtual(uniqueID: .init(id: UUID().uuidString)) let name: String? } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift index 5d5322a4d0..94654d2df4 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift @@ -6,6 +6,7 @@ // import Foundation +import MatrixRustSDK final class RoomTimelineItemViewState: Identifiable, Equatable, ObservableObject { @Published var type: RoomTimelineItemType @@ -34,7 +35,7 @@ final class RoomTimelineItemViewState: Identifiable, Equatable, ObservableObject // MARK: Identifiable /// The `timelineID` of the item, used for the timeline view level identification, do not use for any business logic use `identifier` instead - var id: String { + var id: TimelineUniqueId { identifier.uniqueID } } diff --git a/ElementX/Sources/Services/Timeline/TimelineProxy.swift b/ElementX/Sources/Services/Timeline/TimelineProxy.swift index 74fe851ae4..160eff7911 100644 --- a/ElementX/Sources/Services/Timeline/TimelineProxy.swift +++ b/ElementX/Sources/Services/Timeline/TimelineProxy.swift @@ -179,22 +179,17 @@ final class TimelineProxy: TimelineProxyProtocol { } } - func redact(_ timelineItemID: TimelineItemIdentifier, reason: String?) async -> Result { - MXLog.info("Redacting timeline item: \(timelineItemID)") - - guard let eventOrTransactionID = await timelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID)?.eventOrTransactionId else { - MXLog.error("Unknown timeline item: \(timelineItemID)") - return .failure(.failedRedacting) - } + func redact(_ eventOrTransactionID: EventOrTransactionId, reason: String?) async -> Result { + MXLog.info("Redacting timeline item: \(eventOrTransactionID)") do { try await timeline.redactEvent(eventOrTransactionId: eventOrTransactionID, reason: reason) - MXLog.info("Redacted timeline item: \(timelineItemID)") + MXLog.info("Redacted timeline item: \(eventOrTransactionID)") return .success(()) } catch { - MXLog.error("Failed redacting timeline item: \(timelineItemID) with error: \(error)") + MXLog.error("Failed redacting timeline item: \(eventOrTransactionID) with error: \(error)") return .failure(.sdkError(error)) } } @@ -426,15 +421,15 @@ final class TimelineProxy: TimelineProxyProtocol { } } - func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async -> Result { - MXLog.info("Toggling reaction for event: \(itemID)") + func toggleReaction(_ reaction: String, to eventOrTransactionID: EventOrTransactionId) async -> Result { + MXLog.info("Toggling reaction \(reaction) for event: \(eventOrTransactionID)") do { - try await timeline.toggleReaction(uniqueId: itemID.uniqueID, key: reaction) - MXLog.info("Finished toggling reaction for event: \(itemID)") + try await timeline.toggleReaction(itemId: eventOrTransactionID, key: reaction) + MXLog.info("Finished toggling reaction for event: \(eventOrTransactionID)") return .success(()) } catch { - MXLog.error("Failed toggling reaction for event: \(itemID)") + MXLog.error("Failed toggling reaction for event: \(eventOrTransactionID)") return .failure(.sdkError(error)) } } diff --git a/ElementX/Sources/Services/Timeline/TimelineProxyProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineProxyProtocol.swift index 0f18fa5db0..9301314132 100644 --- a/ElementX/Sources/Services/Timeline/TimelineProxyProtocol.swift +++ b/ElementX/Sources/Services/Timeline/TimelineProxyProtocol.swift @@ -41,7 +41,7 @@ protocol TimelineProxyProtocol { func edit(_ eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation) async -> Result - func redact(_ timelineItemID: TimelineItemIdentifier, + func redact(_ eventOrTransactionID: EventOrTransactionId, reason: String?) async -> Result func pin(eventID: String) async -> Result @@ -93,7 +93,7 @@ protocol TimelineProxyProtocol { inReplyToEventID: String?, intentionalMentions: IntentionalMentions) async -> Result - func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async -> Result + func toggleReaction(_ reaction: String, to eventID: EventOrTransactionId) async -> Result func createPoll(question: String, answers: [String], pollKind: Poll.Kind) async -> Result diff --git a/UnitTests/Sources/LoggingTests.swift b/UnitTests/Sources/LoggingTests.swift index 6887809a5a..20205e5209 100644 --- a/UnitTests/Sources/LoggingTests.swift +++ b/UnitTests/Sources/LoggingTests.swift @@ -195,25 +195,25 @@ class LoggingTests: XCTestCase { } let content = try String(contentsOf: logFile) - XCTAssertTrue(content.contains(textMessage.id.uniqueID)) + XCTAssertTrue(content.contains(textMessage.id.uniqueID.id)) XCTAssertFalse(content.contains(textMessage.body)) XCTAssertFalse(content.contains(textAttributedString)) - XCTAssertTrue(content.contains(noticeMessage.id.uniqueID)) + XCTAssertTrue(content.contains(noticeMessage.id.uniqueID.id)) XCTAssertFalse(content.contains(noticeMessage.body)) XCTAssertFalse(content.contains(noticeAttributedString)) - XCTAssertTrue(content.contains(emoteMessage.id.uniqueID)) + XCTAssertTrue(content.contains(emoteMessage.id.uniqueID.id)) XCTAssertFalse(content.contains(emoteMessage.body)) XCTAssertFalse(content.contains(emoteAttributedString)) - XCTAssertTrue(content.contains(imageMessage.id.uniqueID)) + XCTAssertTrue(content.contains(imageMessage.id.uniqueID.id)) XCTAssertFalse(content.contains(imageMessage.body)) - XCTAssertTrue(content.contains(videoMessage.id.uniqueID)) + XCTAssertTrue(content.contains(videoMessage.id.uniqueID.id)) XCTAssertFalse(content.contains(videoMessage.body)) - XCTAssertTrue(content.contains(fileMessage.id.uniqueID)) + XCTAssertTrue(content.contains(fileMessage.id.uniqueID.id)) XCTAssertFalse(content.contains(fileMessage.body)) } diff --git a/UnitTests/Sources/MessageForwardingScreenViewModelTests.swift b/UnitTests/Sources/MessageForwardingScreenViewModelTests.swift index e96a8e2402..3076a40aa7 100644 --- a/UnitTests/Sources/MessageForwardingScreenViewModelTests.swift +++ b/UnitTests/Sources/MessageForwardingScreenViewModelTests.swift @@ -12,7 +12,7 @@ import XCTest @MainActor class MessageForwardingScreenViewModelTests: XCTestCase { - let forwardingItem = MessageForwardingItem(id: .event(uniqueID: "t1", eventOrTransactionID: .eventId(eventId: "t1")), + let forwardingItem = MessageForwardingItem(id: .event(uniqueID: .init(id: "t1"), eventOrTransactionID: .eventId(eventId: "t1")), roomID: "1", content: .init(noPointer: .init())) var viewModel: MessageForwardingScreenViewModelProtocol! diff --git a/UnitTests/Sources/RoomScreenViewModelTests.swift b/UnitTests/Sources/RoomScreenViewModelTests.swift index 43b8cf10c9..e21891bb43 100644 --- a/UnitTests/Sources/RoomScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomScreenViewModelTests.swift @@ -69,8 +69,8 @@ class RoomScreenViewModelTests: XCTestCase { let providerUpdateSubject = PassthroughSubject<([TimelineItemProxy], PaginationState), Never>() pinnedTimelineProviderMock.underlyingUpdatePublisher = providerUpdateSubject.eraseToAnyPublisher() pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock - pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: "1")), - .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: "2"))] + pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init(id: "1"))), + .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init(id: "2")))] // check if the banner is now in a loaded state and is showing the counter deferred = deferFulfillment(viewModel.context.$viewState) { viewState in @@ -86,9 +86,9 @@ class RoomScreenViewModelTests: XCTestCase { deferred = deferFulfillment(viewModel.context.$viewState) { viewState in viewState.pinnedEventsBannerState.count == 3 } - providerUpdateSubject.send(([.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: "1")), - .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: "2")), - .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: "3"))], .initial)) + providerUpdateSubject.send(([.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init(id: "1"))), + .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init(id: "2"))), + .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: .init(id: "3")))], .initial)) try await deferred.fulfill() XCTAssertFalse(viewModel.context.viewState.pinnedEventsBannerState.isLoading) XCTAssertTrue(viewModel.context.viewState.shouldShowPinnedEventsBanner) @@ -109,9 +109,9 @@ class RoomScreenViewModelTests: XCTestCase { let pinnedTimelineProviderMock = RoomTimelineProviderMock() pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock pinnedTimelineProviderMock.underlyingUpdatePublisher = Empty<([TimelineItemProxy], PaginationState), Never>().eraseToAnyPublisher() - pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: "1")), - .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: "2")), - .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: "3"))] + pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init(id: "1"))), + .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init(id: "2"))), + .event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: .init(id: "3")))] roomProxyMock.underlyingPinnedEventsTimeline = pinnedTimelineMock let viewModel = RoomScreenViewModel(clientProxy: ClientProxyMock(), roomProxy: roomProxyMock, diff --git a/UnitTests/Sources/TimelineItemFactoryTests.swift b/UnitTests/Sources/TimelineItemFactoryTests.swift index 0ca14f8fac..9033adda4e 100644 --- a/UnitTests/Sources/TimelineItemFactoryTests.swift +++ b/UnitTests/Sources/TimelineItemFactoryTests.swift @@ -22,7 +22,7 @@ class TimelineItemFactoryTests: XCTestCase { let eventTimelineItem = EventTimelineItem.mockCallInvite(sender: senderUserID) - let eventTimelineItemProxy = EventTimelineItemProxy(item: eventTimelineItem, uniqueID: "0") + let eventTimelineItemProxy = EventTimelineItemProxy(item: eventTimelineItem, uniqueID: .init(id: "0")) let item = factory.buildTimelineItem(for: eventTimelineItemProxy, isDM: false) diff --git a/UnitTests/Sources/TimelineViewModelTests.swift b/UnitTests/Sources/TimelineViewModelTests.swift index 6625562c3f..d0a95e8131 100644 --- a/UnitTests/Sources/TimelineViewModelTests.swift +++ b/UnitTests/Sources/TimelineViewModelTests.swift @@ -8,6 +8,7 @@ @testable import ElementX import Combine +import MatrixRustSDK import XCTest @MainActor @@ -258,9 +259,9 @@ class TimelineViewModelTests: XCTestCase { func testSendReadReceiptWithoutEvents() async throws { // Given a room with only virtual items. - let items = [SeparatorRoomTimelineItem(uniqueID: "v1"), - SeparatorRoomTimelineItem(uniqueID: "v2"), - SeparatorRoomTimelineItem(uniqueID: "v3")] + let items = [SeparatorRoomTimelineItem(uniqueID: .init(id: "v1")), + SeparatorRoomTimelineItem(uniqueID: .init(id: "v2")), + SeparatorRoomTimelineItem(uniqueID: .init(id: "v3"))] let (viewModel, _, timelineProxy, _) = readReceiptsConfiguration(with: items) // When sending a read receipt for the last item. @@ -275,7 +276,7 @@ class TimelineViewModelTests: XCTestCase { // Given a room where the last event is a virtual item. let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"), TextRoomTimelineItem(eventID: "t2"), - SeparatorRoomTimelineItem(uniqueID: "v3")] + SeparatorRoomTimelineItem(uniqueID: .init(id: "v3"))] let (viewModel, _, _, _) = readReceiptsConfiguration(with: items) // When sending a read receipt for the last item. @@ -436,14 +437,14 @@ private extension TextRoomTimelineItem { } private extension SeparatorRoomTimelineItem { - init(uniqueID: String) { + init(uniqueID: TimelineUniqueId) { self.init(id: .virtual(uniqueID: uniqueID), text: "") } } private extension TextRoomTimelineItem { init(eventID: String) { - self.init(id: .event(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: eventID)), + self.init(id: .event(uniqueID: .init(id: UUID().uuidString), eventOrTransactionID: .eventId(eventId: eventID)), timestamp: "", isOutgoing: false, isEditable: false, diff --git a/project.yml b/project.yml index 1064f024d8..f7fde5a70e 100644 --- a/project.yml +++ b/project.yml @@ -60,7 +60,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/element-hq/matrix-rust-components-swift - exactVersion: 1.0.57 + exactVersion: 1.0.58 # path: ../matrix-rust-sdk Compound: url: https://github.com/element-hq/compound-ios