diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 503320365..888be39a8 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -3146,6 +3146,44 @@ class RoomProxyMock: RoomProxyProtocol { return elementCallWidgetDriverReturnValue } } + //MARK: - matrixToPermalink + + var matrixToPermalinkCallsCount = 0 + var matrixToPermalinkCalled: Bool { + return matrixToPermalinkCallsCount > 0 + } + var matrixToPermalinkReturnValue: Result! + var matrixToPermalinkClosure: (() async -> Result)? + + func matrixToPermalink() async -> Result { + matrixToPermalinkCallsCount += 1 + if let matrixToPermalinkClosure = matrixToPermalinkClosure { + return await matrixToPermalinkClosure() + } else { + return matrixToPermalinkReturnValue + } + } + //MARK: - matrixToEventPermalink + + var matrixToEventPermalinkCallsCount = 0 + var matrixToEventPermalinkCalled: Bool { + return matrixToEventPermalinkCallsCount > 0 + } + var matrixToEventPermalinkReceivedEventID: String? + var matrixToEventPermalinkReceivedInvocations: [String] = [] + var matrixToEventPermalinkReturnValue: Result! + var matrixToEventPermalinkClosure: ((String) async -> Result)? + + func matrixToEventPermalink(_ eventID: String) async -> Result { + matrixToEventPermalinkCallsCount += 1 + matrixToEventPermalinkReceivedEventID = eventID + matrixToEventPermalinkReceivedInvocations.append(eventID) + if let matrixToEventPermalinkClosure = matrixToEventPermalinkClosure { + return await matrixToEventPermalinkClosure(eventID) + } else { + return matrixToEventPermalinkReturnValue + } + } } class RoomSummaryProviderMock: RoomSummaryProviderProtocol { var roomListPublisher: CurrentValuePublisher<[RoomSummary], Never> { diff --git a/ElementX/Sources/Mocks/RoomProxyMock.swift b/ElementX/Sources/Mocks/RoomProxyMock.swift index 9ae37196b..665117627 100644 --- a/ElementX/Sources/Mocks/RoomProxyMock.swift +++ b/ElementX/Sources/Mocks/RoomProxyMock.swift @@ -132,5 +132,8 @@ extension RoomProxyMock { widgetDriver.startBaseURLClientIDReturnValue = .success(url) elementCallWidgetDriverReturnValue = widgetDriver + + matrixToPermalinkReturnValue = .success(.homeDirectory) + matrixToEventPermalinkReturnValue = .success(.homeDirectory) } } diff --git a/ElementX/Sources/Other/PermalinkBuilder.swift b/ElementX/Sources/Other/PermalinkBuilder.swift index c24fae060..6c8c97cee 100644 --- a/ElementX/Sources/Other/PermalinkBuilder.swift +++ b/ElementX/Sources/Other/PermalinkBuilder.swift @@ -92,6 +92,7 @@ enum PermalinkBuilder { return url } + @available(*, deprecated, message: "Use a room's `matrixToPermalink` method instead") static func permalinkTo(roomIdentifier: String, baseURL: URL) throws -> URL { guard MatrixEntityRegex.isMatrixRoomIdentifier(roomIdentifier) else { throw PermalinkBuilderError.invalidRoomIdentifier @@ -100,6 +101,7 @@ enum PermalinkBuilder { return try permalinkTo(roomIdentifierOrAlias: roomIdentifier, baseURL: baseURL) } + @available(*, deprecated, message: "Use a room's `matrixToPermalink` method instead") static func permalinkTo(roomAlias: String, baseURL: URL) throws -> URL { guard MatrixEntityRegex.isMatrixRoomAlias(roomAlias) else { throw PermalinkBuilderError.invalidRoomAlias @@ -108,6 +110,7 @@ enum PermalinkBuilder { return try permalinkTo(roomIdentifierOrAlias: roomAlias, baseURL: baseURL) } + @available(*, deprecated, message: "Use a room's `matrixToEventPermalink` method instead") static func permalinkTo(eventIdentifier: String, roomIdentifier: String, baseURL: URL) throws -> URL { guard MatrixEntityRegex.isMatrixEventIdentifier(eventIdentifier) else { throw PermalinkBuilderError.invalidEventIdentifier diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift index 177150bf0..4fb732747 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift @@ -38,7 +38,7 @@ struct RoomDetailsScreenViewState: BindableState { let isEncrypted: Bool let isDirect: Bool - let permalink: URL? + var permalink: URL? var topic: AttributedString? var topicSummary: AttributedString? diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift index 17d55c91f..54ecaaaca 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift @@ -59,7 +59,6 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr super.init(initialViewState: .init(details: roomProxy.details, isEncrypted: roomProxy.isEncrypted, isDirect: roomProxy.isDirect, - permalink: roomProxy.permalink, topic: topic, topicSummary: topic?.unattributedStringByReplacingNewlinesWithSpaces(), joinedMembersCount: roomProxy.joinedMembersCount, @@ -67,6 +66,12 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr bindings: .init()), imageProvider: mediaProvider) + Task { + if case let .success(permalinkURL) = await roomProxy.matrixToPermalink() { + state.permalink = permalinkURL + } + } + updateRoomInfo() Task { await updatePowerLevelPermissions() } diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenInteractionHandler.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenInteractionHandler.swift index 5aa9ad225..9524aeb9c 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenInteractionHandler.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenInteractionHandler.swift @@ -208,17 +208,18 @@ class RoomScreenInteractionHandler { MXLog.error("Cannot edit item with id: \(timelineItem.id)") } case .copyPermalink: - do { - guard let eventID = eventTimelineItem.id.eventID else { - actionsSubject.send(.displayError(.alert(L10n.errorFailedCreatingThePermalink))) - break - } - - let permalink = try PermalinkBuilder.permalinkTo(eventIdentifier: eventID, roomIdentifier: timelineController.roomID, - baseURL: appSettings.permalinkBaseURL) - UIPasteboard.general.url = permalink - } catch { + guard let eventID = eventTimelineItem.id.eventID else { actionsSubject.send(.displayError(.alert(L10n.errorFailedCreatingThePermalink))) + return + } + + Task { + guard case let .success(permalinkURL) = await roomProxy.matrixToEventPermalink(eventID) else { + actionsSubject.send(.displayError(.alert(L10n.errorFailedCreatingThePermalink))) + return + } + + UIPasteboard.general.url = permalinkURL } case .redact: Task { diff --git a/ElementX/Sources/Services/Room/RoomProxy.swift b/ElementX/Sources/Services/Room/RoomProxy.swift index c7e20ac24..22ec58c3d 100644 --- a/ElementX/Sources/Services/Room/RoomProxy.swift +++ b/ElementX/Sources/Services/Room/RoomProxy.swift @@ -528,6 +528,40 @@ class RoomProxy: RoomProxyProtocol { func elementCallWidgetDriver() -> ElementCallWidgetDriverProtocol { ElementCallWidgetDriver(room: room) } + + // MARK: - Permalinks + + func matrixToPermalink() async -> Result { + do { + let urlString = try await room.matrixToPermalink() + + guard let url = URL(string: urlString) else { + MXLog.error("Invalid permalink URL string: \(urlString)") + return .failure(.generic("Invalid permalink URL string: \(urlString)")) + } + + return .success(url) + } catch { + MXLog.error("Failed creating permalink for roomID: \(id) with error: \(error)") + return .failure(.generic(error.localizedDescription)) + } + } + + func matrixToEventPermalink(_ eventID: String) async -> Result { + do { + let urlString = try await room.matrixToEventPermalink(eventId: eventID) + + guard let url = URL(string: urlString) else { + MXLog.error("Invalid permalink URL string: \(urlString)") + return .failure(.generic("Invalid permalink URL string: \(urlString)")) + } + + return .success(url) + } catch { + MXLog.error("Failed creating permalink for eventID: \(eventID) with error: \(error)") + return .failure(.generic(error.localizedDescription)) + } + } // MARK: - Private diff --git a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift index 7e864b3eb..9edfd310b 100644 --- a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift @@ -19,6 +19,7 @@ import Foundation import MatrixRustSDK enum RoomProxyError: Error, Equatable { + case generic(String?) case failedRedactingEvent case failedReportingContent case failedRetrievingMember @@ -139,6 +140,12 @@ protocol RoomProxyProtocol { func canUserJoinCall(userID: String) async -> Result func elementCallWidgetDriver() -> ElementCallWidgetDriverProtocol + + // MARK: - Permalinks + + func matrixToPermalink() async -> Result + + func matrixToEventPermalink(_ eventID: String) async -> Result } extension RoomProxyProtocol { @@ -148,20 +155,7 @@ extension RoomProxyProtocol { avatarURL: avatarURL, canonicalAlias: canonicalAlias) } - - var permalink: URL? { - if let canonicalAlias, let link = try? PermalinkBuilder.permalinkTo(roomAlias: canonicalAlias, - baseURL: ServiceLocator.shared.settings.permalinkBaseURL) { - return link - } else if let link = try? PermalinkBuilder.permalinkTo(roomIdentifier: id, - baseURL: ServiceLocator.shared.settings.permalinkBaseURL) { - return link - } else { - MXLog.error("Failed to build permalink for Room: \(id)") - return nil - } - } - + // Avoids to duplicate the same logic around in the app // Probably this should be done in rust. var roomTitle: String {