From 75ea2f55c404538db892ebf3d337ec600355a372 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Tue, 22 Jul 2025 14:33:26 +0300 Subject: [PATCH] Add message sending methods to the `TimelineController` that will automatically use the correct timeline proxy instance internally. --- .../MockTimelineController.swift | 86 ++++++++++++++++++- .../TimelineController.swift | 59 ++++++++++++- .../TimelineControllerProtocol.swift | 34 +++++++- .../VoiceMessage/VoiceMessageRecorder.swift | 2 +- 4 files changed, 175 insertions(+), 6 deletions(-) diff --git a/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift index c272ce3ff..9779bdd56 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift @@ -155,14 +155,96 @@ class MockTimelineController: TimelineControllerProtocol { inReplyToEventID: String?, intentionalMentions: IntentionalMentions) async { } - func sendVoiceMessage(url: URL, audioInfo: AudioInfo, waveform: [UInt16]) async -> Result { + func sendAudio(url: URL, + audioInfo: MatrixRustSDK.AudioInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { if let timelineProxy { - return await timelineProxy.sendVoiceMessage(url: url, audioInfo: audioInfo, waveform: waveform) { _ in } + return await timelineProxy.sendAudio(url: url, + audioInfo: audioInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) } return .success(()) } + func sendFile(url: URL, + fileInfo: MatrixRustSDK.FileInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + if let timelineProxy { + return await timelineProxy.sendFile(url: url, + fileInfo: fileInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + return .success(()) + } + + func sendImage(url: URL, + thumbnailURL: URL, + imageInfo: MatrixRustSDK.ImageInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + if let timelineProxy { + return await timelineProxy.sendImage(url: url, + thumbnailURL: thumbnailURL, + imageInfo: imageInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + return .success(()) + } + + func sendLocation(body: String, + geoURI: GeoURI, + description: String?, + zoomLevel: UInt8?, + assetType: MatrixRustSDK.AssetType?) async -> Result { + if let timelineProxy { + return await timelineProxy.sendLocation(body: body, + geoURI: geoURI, + description: description, + zoomLevel: zoomLevel, + assetType: assetType).mapError(TimelineControllerError.timelineProxyError) + } + + return .success(()) + } + + func sendVideo(url: URL, + thumbnailURL: URL, + videoInfo: MatrixRustSDK.VideoInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + if let timelineProxy { + return await timelineProxy.sendVideo(url: url, + thumbnailURL: thumbnailURL, + videoInfo: videoInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + return .success(()) + } + + func sendVoiceMessage(url: URL, + audioInfo: MatrixRustSDK.AudioInfo, + waveform: [UInt16], + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + if let timelineProxy { + return await timelineProxy.sendVoiceMessage(url: url, + audioInfo: audioInfo, + waveform: waveform, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + return .success(()) + } + // MARK: - UI Test signalling /// The cancellable used for UI Tests signalling. diff --git a/ElementX/Sources/Services/Timeline/TimelineController/TimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/TimelineController.swift index d551a19f4..a57de03d6 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/TimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/TimelineController.swift @@ -301,10 +301,65 @@ class TimelineController: TimelineControllerProtocol { } } - func sendVoiceMessage(url: URL, audioInfo: AudioInfo, waveform: [UInt16]) async -> Result { + func sendAudio(url: URL, + audioInfo: MatrixRustSDK.AudioInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + await activeTimeline.sendAudio(url: url, + audioInfo: audioInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + func sendFile(url: URL, + fileInfo: MatrixRustSDK.FileInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + await activeTimeline.sendFile(url: url, + fileInfo: fileInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + func sendImage(url: URL, + thumbnailURL: URL, + imageInfo: MatrixRustSDK.ImageInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + await activeTimeline.sendImage(url: url, + thumbnailURL: thumbnailURL, + imageInfo: imageInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + func sendVideo(url: URL, + thumbnailURL: URL, + videoInfo: MatrixRustSDK.VideoInfo, + caption: String?, + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { + await activeTimeline.sendVideo(url: url, + thumbnailURL: thumbnailURL, + videoInfo: videoInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + + func sendLocation(body: String, + geoURI: GeoURI, + description: String?, + zoomLevel: UInt8?, + assetType: AssetType?) async -> Result { + await activeTimeline.sendLocation(body: body, geoURI: geoURI, description: description, zoomLevel: zoomLevel, assetType: assetType).mapError(TimelineControllerError.timelineProxyError) + } + + func sendVoiceMessage(url: URL, + audioInfo: MatrixRustSDK.AudioInfo, + waveform: [UInt16], + requestHandle: @MainActor (any MatrixRustSDK.SendAttachmentJoinHandleProtocol) -> Void) async -> Result { await activeTimeline.sendVoiceMessage(url: url, audioInfo: audioInfo, - waveform: waveform) { _ in } + waveform: waveform, requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) } // MARK: - Private diff --git a/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerProtocol.swift index ab6e3e102..8696a0518 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerProtocol.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/TimelineControllerProtocol.swift @@ -31,6 +31,7 @@ enum TimelineControllerAction { enum TimelineControllerError: Error { case generic case eventNotFound + case timelineProxyError(TimelineProxyError) } /// This protocol is a high level abstraction on top of the ``TimelineProxyProtocol`` @@ -98,5 +99,36 @@ protocol TimelineControllerProtocol { inReplyToEventID: String?, intentionalMentions: IntentionalMentions) async - func sendVoiceMessage(url: URL, audioInfo: AudioInfo, waveform: [UInt16]) async -> Result + func sendAudio(url: URL, + audioInfo: AudioInfo, + caption: String?, + requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result + + func sendFile(url: URL, + fileInfo: FileInfo, + caption: String?, + requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result + + func sendImage(url: URL, + thumbnailURL: URL, + imageInfo: ImageInfo, + caption: String?, + requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result + + func sendLocation(body: String, + geoURI: GeoURI, + description: String?, + zoomLevel: UInt8?, + assetType: AssetType?) async -> Result + + func sendVideo(url: URL, + thumbnailURL: URL, + videoInfo: VideoInfo, + caption: String?, + requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result + + func sendVoiceMessage(url: URL, + audioInfo: AudioInfo, + waveform: [UInt16], + requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result } diff --git a/ElementX/Sources/Services/VoiceMessage/VoiceMessageRecorder.swift b/ElementX/Sources/Services/VoiceMessage/VoiceMessageRecorder.swift index 7b48523c7..351773760 100644 --- a/ElementX/Sources/Services/VoiceMessage/VoiceMessageRecorder.swift +++ b/ElementX/Sources/Services/VoiceMessage/VoiceMessageRecorder.swift @@ -179,7 +179,7 @@ class VoiceMessageRecorder: VoiceMessageRecorderProtocol { let result = await timelineController.sendVoiceMessage(url: oggFile, audioInfo: audioInfo, - waveform: waveform) + waveform: waveform) { _ in } if case .failure(let error) = result { MXLog.error("Failed to send the voice message. \(error)")