diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index f35ee799d3..f731ede2e6 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1803C82027FDE17B00795848 /* MediaSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1803C81F27FDE17B00795848 /* MediaSource.swift */; }; 181A317727F703E300B8305B /* RoomSummaryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181A317427F703E300B8305B /* RoomSummaryProtocol.swift */; }; 181A317827F703E300B8305B /* RoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181A317527F703E300B8305B /* RoomSummary.swift */; }; 181A317927F703E300B8305B /* MockRoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181A317627F703E300B8305B /* MockRoomSummary.swift */; }; @@ -150,6 +151,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 1803C81F27FDE17B00795848 /* MediaSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaSource.swift; sourceTree = ""; }; 181A317427F703E300B8305B /* RoomSummaryProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomSummaryProtocol.swift; sourceTree = ""; }; 181A317527F703E300B8305B /* RoomSummary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = ""; }; 181A317627F703E300B8305B /* MockRoomSummary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockRoomSummary.swift; sourceTree = ""; }; @@ -189,7 +191,6 @@ 18ADC80427EB1ED100A8C953 /* UIFont+AttributedStringBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+AttributedStringBuilder.m"; sourceTree = ""; }; 18ADC80527EB1ED100A8C953 /* UIFont+AttributedStringBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIFont+AttributedStringBuilder.h"; sourceTree = ""; }; 18ADC80727EB1EE200A8C953 /* ElementX-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ElementX-Bridging-Header.h"; sourceTree = ""; }; - 18BB170627FB74B30074CBD6 /* matrix-rust-components-swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "matrix-rust-components-swift"; path = "../matrix-rust-components-swift"; sourceTree = ""; }; 18BB170927FC20D20074CBD6 /* BlurHashDecode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; 18C5744827E1D84000D70937 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = ""; }; 18C5744A27E1D84000D70937 /* RoomProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomProxy.swift; sourceTree = ""; }; @@ -323,7 +324,6 @@ 1850251B27B6918C002E6B18 = { isa = PBXGroup; children = ( - 18BB170627FB74B30074CBD6 /* matrix-rust-components-swift */, 1850252627B6918C002E6B18 /* ElementX */, 1850253D27B6918D002E6B18 /* ElementXTests */, 1850254727B6918D002E6B18 /* ElementXUITests */, @@ -460,6 +460,7 @@ 18DF7C3027E3608100291672 /* MediaProviderProtocol.swift */, 18DF7C2E27E264FC00291672 /* MediaProvider.swift */, 18DF7C3227E3608800291672 /* MockMediaProvider.swift */, + 1803C81F27FDE17B00795848 /* MediaSource.swift */, ); path = Media; sourceTree = ""; @@ -1044,6 +1045,7 @@ 18F2BAFB27D25B4000DD1988 /* HomeScreenCoordinator.swift in Sources */, 18F2BB0C27D25B4000DD1988 /* RoomScreenCoordinator.swift in Sources */, 18DDB72127EB9D57000F1ABF /* ElementXAttributeScope.swift in Sources */, + 1803C82027FDE17B00795848 /* MediaSource.swift in Sources */, 18DF7C4527E4670600291672 /* SeparatorRoomTimelineItem.swift in Sources */, 18DF7C4227E4670600291672 /* RoomTimelineItemFactory.swift in Sources */, 18F2BB0E27D25B4000DD1988 /* RoomScreenViewModelProtocol.swift in Sources */, diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index eead87e7bc..661414b2f8 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -42,7 +42,7 @@ "repositoryURL": "https://github.com/matrix-org/matrix-rust-components-swift.git", "state": { "branch": "main", - "revision": "a69956b5724cc969ea47acf5eabbacdfecc712b7", + "revision": "f6682cf02eec087f921c53526895996cba169378", "version": null } }, diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/ImageRoomTimelineView.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/ImageRoomTimelineView.swift index 076571ffcb..948f8c59c0 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Timeline/ImageRoomTimelineView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Timeline/ImageRoomTimelineView.swift @@ -65,7 +65,7 @@ struct ImageRoomTimelineView_Previews: PreviewProvider { timestamp: "Now", shouldShowSenderDetails: false, senderId: "Bob", - url: nil, + source: nil, image: UIImage(systemName: "photo")) ImageRoomTimelineView(timelineItem: timelineItem) @@ -74,7 +74,7 @@ struct ImageRoomTimelineView_Previews: PreviewProvider { timestamp: "Now", shouldShowSenderDetails: false, senderId: "Bob", - url: nil, + source: nil, image: nil) ImageRoomTimelineView(timelineItem: timelineItem) @@ -83,7 +83,7 @@ struct ImageRoomTimelineView_Previews: PreviewProvider { timestamp: "Now", shouldShowSenderDetails: false, senderId: "Bob", - url: nil, + source: nil, image: nil, aspectRatio: 0.7, blurhash: "L%KUc%kqS$RP?Ks,WEf8OlrqaekW") diff --git a/ElementX/Sources/Services/Media/MediaProvider.swift b/ElementX/Sources/Services/Media/MediaProvider.swift index 9d37f4dc5a..8896af0263 100644 --- a/ElementX/Sources/Services/Media/MediaProvider.swift +++ b/ElementX/Sources/Services/Media/MediaProvider.swift @@ -21,21 +21,21 @@ struct MediaProvider: MediaProviderProtocol { self.processingQueue = DispatchQueue(label: "MediaProviderProcessingQueue", attributes: .concurrent) } - func imageForURL(_ url: String?) -> UIImage? { - guard let url = url else { + func imageFromSource(_ source: MediaSource?) -> UIImage? { + guard let source = source else { return nil } - - return imageCache.retrieveImageInMemoryCache(forKey: url, options: nil) + + return imageCache.retrieveImageInMemoryCache(forKey: source.underlyingSource.url(), options: nil) } - func loadImageFromURL(_ url: String, _ completion: @escaping (Result) -> Void) { - if let image = imageForURL(url) { + func loadImageFromSource(_ source: MediaSource, _ completion: @escaping (Result) -> Void) { + if let image = imageFromSource(source) { completion(.success(image)) return } - imageCache.retrieveImage(forKey: url) { result in + imageCache.retrieveImage(forKey: source.underlyingSource.url()) { result in if case let .success(cacheResult) = result, let image = cacheResult.image { completion(.success(image)) @@ -44,7 +44,7 @@ struct MediaProvider: MediaProviderProtocol { processingQueue.async { do { - let imageData = try client.loadImage(url: url) + let imageData = try client.loadImage(source: source.underlyingSource) guard let image = UIImage(data: Data(bytes: imageData, count: imageData.count)) else { MXLog.error("Invalid image data") @@ -54,7 +54,7 @@ struct MediaProvider: MediaProviderProtocol { return } - imageCache.store(image, forKey: url) + imageCache.store(image, forKey: source.underlyingSource.url()) DispatchQueue.main.async { completion(.success(image)) @@ -68,4 +68,16 @@ struct MediaProvider: MediaProviderProtocol { } } } + + func imageFromURL(_ url: String?) -> UIImage? { + guard let url = url else { + return nil + } + + return imageFromSource(MediaSource(source: mediaSourceFromUrl(url: url))) + } + + func loadImageFromURL(_ url: String, _ completion: @escaping (Result) -> Void) { + return loadImageFromSource(MediaSource(source: mediaSourceFromUrl(url: url)), completion) + } } diff --git a/ElementX/Sources/Services/Media/MediaProviderProtocol.swift b/ElementX/Sources/Services/Media/MediaProviderProtocol.swift index 03ff93c13d..5768e98b8e 100644 --- a/ElementX/Sources/Services/Media/MediaProviderProtocol.swift +++ b/ElementX/Sources/Services/Media/MediaProviderProtocol.swift @@ -15,7 +15,11 @@ enum MediaProviderError: Error { } protocol MediaProviderProtocol { - func imageForURL(_ url: String?) -> UIImage? + func imageFromSource(_ source: MediaSource?) -> UIImage? + + func loadImageFromSource(_ source: MediaSource, _ completion: @escaping (Result) -> Void) + + func imageFromURL(_ url: String?) -> UIImage? func loadImageFromURL(_ url: String, _ completion: @escaping (Result) -> Void) } diff --git a/ElementX/Sources/Services/Media/MediaSource.swift b/ElementX/Sources/Services/Media/MediaSource.swift new file mode 100644 index 0000000000..c6f37c1611 --- /dev/null +++ b/ElementX/Sources/Services/Media/MediaSource.swift @@ -0,0 +1,28 @@ +// +// MediaSource.swift +// ElementX +// +// Created by Stefan Ceriu on 06/04/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import MatrixRustSDK + +struct MediaSource: Equatable { + let underlyingSource: MatrixRustSDK.MediaSource + + init(source: MatrixRustSDK.MediaSource) { + self.underlyingSource = source + } + + init(urlString: String) { + self.underlyingSource = mediaSourceFromUrl(url: urlString) + } + + // MARK: - Equatable + + static func == (lhs: MediaSource, rhs: MediaSource) -> Bool { + return lhs.underlyingSource.url() == rhs.underlyingSource.url() + } +} diff --git a/ElementX/Sources/Services/Media/MockMediaProvider.swift b/ElementX/Sources/Services/Media/MockMediaProvider.swift index 63efb2eca1..384b2eb389 100644 --- a/ElementX/Sources/Services/Media/MockMediaProvider.swift +++ b/ElementX/Sources/Services/Media/MockMediaProvider.swift @@ -15,7 +15,15 @@ struct MockMediaProvider: MediaProviderProtocol { } - func imageForURL(_ url: String?) -> UIImage? { + func imageFromSource(_ source: MediaSource?) -> UIImage? { + return nil + } + + func loadImageFromSource(_ source: MediaSource, _ completion: @escaping (Result) -> Void) { + + } + + func imageFromURL(_ url: String?) -> UIImage? { return nil } diff --git a/ElementX/Sources/Services/Room/Messages/ImageRoomMessage.swift b/ElementX/Sources/Services/Room/Messages/ImageRoomMessage.swift index 3be03f6d7c..f93e931054 100644 --- a/ElementX/Sources/Services/Room/Messages/ImageRoomMessage.swift +++ b/ElementX/Sources/Services/Room/Messages/ImageRoomMessage.swift @@ -32,8 +32,8 @@ struct ImageRoomMessage: RoomMessageProtocol { Date(timeIntervalSince1970: TimeInterval(message.baseMessage().originServerTs())) } - var url: String? { - message.url() + var source: MediaSource? { + MediaSource(source: message.source()) } var width: CGFloat? { diff --git a/ElementX/Sources/Services/Timeline/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/RoomTimelineController.swift index ebe42dfcaa..048b27be4d 100644 --- a/ElementX/Sources/Services/Timeline/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/RoomTimelineController.swift @@ -125,11 +125,11 @@ class RoomTimelineController: RoomTimelineControllerProtocol { return } - guard let url = timelineItem.url else { + guard let source = timelineItem.source else { return } - mediaProvider.loadImageFromURL(url) { [weak self] result in + mediaProvider.loadImageFromSource(source) { [weak self] result in guard let self = self else { return } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/ImageRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/ImageRoomTimelineItem.swift index ddc0cd03ca..be92ed3411 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/ImageRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/ImageRoomTimelineItem.swift @@ -19,7 +19,7 @@ struct ImageRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Equa var senderDisplayName: String? var senderAvatar: UIImage? - let url: String? + let source: MediaSource? var image: UIImage? var width: CGFloat? diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift index 0c72928cf5..546c152606 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift @@ -25,7 +25,7 @@ struct RoomTimelineItemFactory { func buildTimelineItemFor(_ roomMessage: RoomMessageProtocol, showSenderDetails: Bool) -> RoomTimelineItemProtocol { let displayName = memberDetailProvider.displayNameForUserId(roomMessage.sender) let avatarURL = memberDetailProvider.avatarURLForUserId(roomMessage.sender) - let avatarImage = mediaProvider.imageForURL(avatarURL) + let avatarImage = mediaProvider.imageFromURL(avatarURL) switch roomMessage { case let message as TextRoomMessage: @@ -77,8 +77,8 @@ struct RoomTimelineItemFactory { senderId: message.sender, senderDisplayName: displayName, senderAvatar: avatarImage, - url: message.url, - image: mediaProvider.imageForURL(message.url), + source: message.source, + image: mediaProvider.imageFromSource(message.source), width: message.width, height: message.height, aspectRatio: aspectRatio,