mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Timeline item sender profiles (#463)
* Adopt timeline item sender profiles for displaying user avatars and display names * Prevent images from automatically being evicted from the in-memory cache when entering background * Get rid of all the `urlString: String`s and start using proper URLs * Add back manual display name loading as the sender profiles aren't working properly yet * Implement a sender profile. * Bump the RustSDK to v1.0.32-alpha Co-authored-by: Doug <douglase@element.io>
This commit is contained in:
@@ -34,36 +34,37 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
}
|
||||
|
||||
func imageFromSource(_ source: MediaSourceProxy?, avatarSize: AvatarSize?) -> UIImage? {
|
||||
guard let source else {
|
||||
guard let url = source?.url else {
|
||||
return nil
|
||||
}
|
||||
let cacheKey = cacheKeyForURLString(source.url, avatarSize: avatarSize)
|
||||
let cacheKey = cacheKeyForURL(url, avatarSize: avatarSize)
|
||||
return imageCache.retrieveImageInMemoryCache(forKey: cacheKey, options: nil)
|
||||
}
|
||||
|
||||
func imageFromURLString(_ urlString: String?, avatarSize: AvatarSize?) -> UIImage? {
|
||||
guard let urlString else {
|
||||
func imageFromURL(_ url: URL?, avatarSize: AvatarSize?) -> UIImage? {
|
||||
guard let url else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return imageFromSource(.init(urlString: urlString), avatarSize: avatarSize)
|
||||
return imageFromSource(.init(url: url), avatarSize: avatarSize)
|
||||
}
|
||||
|
||||
func loadImageFromURLString(_ urlString: String, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError> {
|
||||
await loadImageFromSource(.init(urlString: urlString), avatarSize: avatarSize)
|
||||
func loadImageFromURL(_ url: URL, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError> {
|
||||
await loadImageFromSource(.init(url: url), avatarSize: avatarSize)
|
||||
}
|
||||
|
||||
func loadImageFromSource(_ source: MediaSourceProxy, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError> {
|
||||
if let image = imageFromSource(source, avatarSize: avatarSize) {
|
||||
return .success(image)
|
||||
}
|
||||
|
||||
|
||||
#warning("Media loading should check for existing in flight operations and de-dupe requests.")
|
||||
let loadImageBgTask = await backgroundTaskService?.startBackgroundTask(withName: "LoadImage: \(source.url.hashValue)")
|
||||
defer {
|
||||
loadImageBgTask?.stop()
|
||||
}
|
||||
|
||||
let cacheKey = cacheKeyForURLString(source.url, avatarSize: avatarSize)
|
||||
let cacheKey = cacheKeyForURL(source.url, avatarSize: avatarSize)
|
||||
|
||||
if case let .success(cacheResult) = await imageCache.retrieveImage(forKey: cacheKey),
|
||||
let image = cacheResult.image {
|
||||
@@ -96,7 +97,7 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
guard let source else {
|
||||
return nil
|
||||
}
|
||||
let cacheKey = fileCacheKeyForURLString(source.url)
|
||||
let cacheKey = fileCacheKeyForURL(source.url)
|
||||
return fileCache.file(forKey: cacheKey, fileExtension: fileExtension)
|
||||
}
|
||||
|
||||
@@ -110,11 +111,11 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
loadFileBgTask?.stop()
|
||||
}
|
||||
|
||||
let cacheKey = fileCacheKeyForURLString(source.url)
|
||||
|
||||
let cacheKey = fileCacheKeyForURL(source.url)
|
||||
|
||||
do {
|
||||
let data = try await mediaProxy.loadMediaContentForSource(source)
|
||||
|
||||
|
||||
let url = try fileCache.store(data, with: fileExtension, forKey: cacheKey)
|
||||
return .success(url)
|
||||
} catch {
|
||||
@@ -122,34 +123,33 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
return .failure(.failedRetrievingImage)
|
||||
}
|
||||
}
|
||||
|
||||
func fileFromURLString(_ urlString: String?, fileExtension: String) -> URL? {
|
||||
guard let urlString else {
|
||||
|
||||
func fileFromURL(_ url: URL?, fileExtension: String) -> URL? {
|
||||
guard let url else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fileFromSource(MediaSourceProxy(urlString: urlString),
|
||||
fileExtension: fileExtension)
|
||||
|
||||
return fileFromSource(MediaSourceProxy(url: url), fileExtension: fileExtension)
|
||||
}
|
||||
|
||||
func loadFileFromURLString(_ urlString: String, fileExtension: String) async -> Result<URL, MediaProviderError> {
|
||||
await loadFileFromSource(MediaSourceProxy(urlString: urlString),
|
||||
fileExtension: fileExtension)
|
||||
|
||||
func loadFileFromURL(_ url: URL, fileExtension: String) async -> Result<URL, MediaProviderError> {
|
||||
await loadFileFromSource(MediaSourceProxy(url: url), fileExtension: fileExtension)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func cacheKeyForURLString(_ urlString: String, avatarSize: AvatarSize?) -> String {
|
||||
private func cacheKeyForURL(_ url: URL, avatarSize: AvatarSize?) -> String {
|
||||
if let avatarSize {
|
||||
return "\(urlString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}"
|
||||
return "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}"
|
||||
} else {
|
||||
return urlString
|
||||
return url.absoluteString
|
||||
}
|
||||
}
|
||||
|
||||
private func fileCacheKeyForURLString(_ urlString: String) -> String {
|
||||
guard let component = urlString.split(separator: "/").last else {
|
||||
return urlString
|
||||
private func fileCacheKeyForURL(_ url: URL) -> String {
|
||||
let component = url.lastPathComponent
|
||||
guard !component.isEmpty else {
|
||||
return url.absoluteString
|
||||
}
|
||||
return String(component)
|
||||
}
|
||||
|
||||
@@ -28,17 +28,17 @@ protocol MediaProviderProtocol {
|
||||
|
||||
@discardableResult func loadImageFromSource(_ source: MediaSourceProxy, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError>
|
||||
|
||||
func imageFromURLString(_ urlString: String?, avatarSize: AvatarSize?) -> UIImage?
|
||||
func imageFromURL(_ url: URL?, avatarSize: AvatarSize?) -> UIImage?
|
||||
|
||||
@discardableResult func loadImageFromURLString(_ urlString: String, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError>
|
||||
@discardableResult func loadImageFromURL(_ url: URL, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError>
|
||||
|
||||
func fileFromSource(_ source: MediaSourceProxy?, fileExtension: String) -> URL?
|
||||
|
||||
@discardableResult func loadFileFromSource(_ source: MediaSourceProxy, fileExtension: String) async -> Result<URL, MediaProviderError>
|
||||
|
||||
func fileFromURLString(_ urlString: String?, fileExtension: String) -> URL?
|
||||
func fileFromURL(_ url: URL?, fileExtension: String) -> URL?
|
||||
|
||||
@discardableResult func loadFileFromURLString(_ urlString: String, fileExtension: String) async -> Result<URL, MediaProviderError>
|
||||
@discardableResult func loadFileFromURL(_ url: URL, fileExtension: String) async -> Result<URL, MediaProviderError>
|
||||
}
|
||||
|
||||
extension MediaProviderProtocol {
|
||||
@@ -50,11 +50,11 @@ extension MediaProviderProtocol {
|
||||
await loadImageFromSource(source, avatarSize: nil)
|
||||
}
|
||||
|
||||
func imageFromURLString(_ urlString: String?) -> UIImage? {
|
||||
imageFromURLString(urlString, avatarSize: nil)
|
||||
func imageFromURL(_ url: URL?) -> UIImage? {
|
||||
imageFromURL(url, avatarSize: nil)
|
||||
}
|
||||
|
||||
@discardableResult func loadImageFromURLString(_ urlString: String) async -> Result<UIImage, MediaProviderError> {
|
||||
await loadImageFromURLString(urlString, avatarSize: nil)
|
||||
@discardableResult func loadImageFromURL(_ url: URL) async -> Result<UIImage, MediaProviderError> {
|
||||
await loadImageFromURL(url, avatarSize: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ class MediaProxy: MediaProxyProtocol {
|
||||
self.clientQueue = clientQueue
|
||||
}
|
||||
|
||||
func mediaSourceForURLString(_ urlString: String) -> MediaSourceProxy {
|
||||
.init(urlString: urlString)
|
||||
func mediaSourceForURL(_ url: URL) -> MediaSourceProxy {
|
||||
.init(url: url)
|
||||
}
|
||||
|
||||
func loadMediaContentForSource(_ source: MediaSourceProxy) async throws -> Data {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import Foundation
|
||||
|
||||
protocol MediaProxyProtocol {
|
||||
func mediaSourceForURLString(_ urlString: String) -> MediaSourceProxy
|
||||
func mediaSourceForURL(_ url: URL) -> MediaSourceProxy
|
||||
|
||||
func loadMediaContentForSource(_ source: MediaSourceProxy) async throws -> Data
|
||||
|
||||
|
||||
@@ -24,12 +24,13 @@ struct MediaSourceProxy: Hashable {
|
||||
underlyingSource = source
|
||||
}
|
||||
|
||||
init(urlString: String) {
|
||||
underlyingSource = mediaSourceFromUrl(url: urlString)
|
||||
init(url: URL) {
|
||||
underlyingSource = mediaSourceFromUrl(url: url.absoluteString)
|
||||
}
|
||||
|
||||
var url: String {
|
||||
underlyingSource.url()
|
||||
var url: URL! {
|
||||
// Expecting these to always be valid URLs
|
||||
URL(string: underlyingSource.url())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ struct MockMediaProvider: MediaProviderProtocol {
|
||||
.failure(.failedRetrievingImage)
|
||||
}
|
||||
|
||||
func imageFromURLString(_ urlString: String?, avatarSize: AvatarSize?) -> UIImage? {
|
||||
guard urlString != nil else {
|
||||
func imageFromURL(_ url: URL?, avatarSize: AvatarSize?) -> UIImage? {
|
||||
guard url != nil else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
if let avatarSize {
|
||||
switch avatarSize {
|
||||
case .room:
|
||||
@@ -41,8 +41,8 @@ struct MockMediaProvider: MediaProviderProtocol {
|
||||
}
|
||||
return UIImage(systemName: "photo")
|
||||
}
|
||||
|
||||
func loadImageFromURLString(_ urlString: String, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError> {
|
||||
|
||||
func loadImageFromURL(_ url: URL, avatarSize: AvatarSize?) async -> Result<UIImage, MediaProviderError> {
|
||||
guard let image = UIImage(systemName: "photo") else {
|
||||
fatalError()
|
||||
}
|
||||
@@ -58,11 +58,11 @@ struct MockMediaProvider: MediaProviderProtocol {
|
||||
.failure(.failedRetrievingFile)
|
||||
}
|
||||
|
||||
func fileFromURLString(_ urlString: String?, fileExtension: String) -> URL? {
|
||||
func fileFromURL(_ url: URL?, fileExtension: String) -> URL? {
|
||||
nil
|
||||
}
|
||||
|
||||
@discardableResult func loadFileFromURLString(_ urlString: String, fileExtension: String) async -> Result<URL, MediaProviderError> {
|
||||
@discardableResult func loadFileFromURL(_ url: URL, fileExtension: String) async -> Result<URL, MediaProviderError> {
|
||||
.failure(.failedRetrievingFile)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user