From 9249a4aeaaed5172f8b2416a5507a5b7d8f02a5a Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 8 Nov 2018 19:20:02 -0500 Subject: [PATCH] Show GIFs in AttachmentView --- Tusker/Caching/ImageCache.swift | 34 +++++++++---------- .../Compose/ComposeViewController.swift | 5 +-- Tusker/Views/AttachmentView.swift | 27 ++++++++++++--- .../ActionNotificationTableViewCell.swift | 10 +++--- .../FollowNotificationTableViewCell.swift | 5 +-- .../ProfileHeaderTableViewCell.swift | 10 +++--- .../ConversationMainStatusTableViewCell.swift | 5 +-- Tusker/Views/Status/StatusTableViewCell.swift | 8 +++-- 8 files changed, 66 insertions(+), 38 deletions(-) diff --git a/Tusker/Caching/ImageCache.swift b/Tusker/Caching/ImageCache.swift index f772a0d8..f7f54742 100644 --- a/Tusker/Caching/ImageCache.swift +++ b/Tusker/Caching/ImageCache.swift @@ -15,31 +15,31 @@ class ImageCache { static let headers = ImageCache(name: "Headers", memoryExpiry: .seconds(60 * 60), diskExpiry: .seconds(60 * 60 * 24)) static let attachments = ImageCache(name: "Attachments", memoryExpiry: .seconds(60 * 2)) - let cache: Cache + let cache: Cache var requests = [URL: Request]() init(name: String, memoryExpiry expiry: Expiry) { - let storage = MemoryStorage(config: MemoryConfig(expiry: expiry)) + let storage = MemoryStorage(config: MemoryConfig(expiry: expiry)) self.cache = .memory(storage) } init(name: String, diskExpiry expiry: Expiry) { - let storage = try! DiskStorage(config: DiskConfig(name: name, expiry: expiry), transformer: TransformerFactory.forImage()) + let storage = try! DiskStorage(config: DiskConfig(name: name, expiry: expiry), transformer: TransformerFactory.forData()) self.cache = .disk(storage) } init(name: String, memoryExpiry: Expiry, diskExpiry: Expiry) { - let memory = MemoryStorage(config: MemoryConfig(expiry: memoryExpiry)) - let disk = try! DiskStorage(config: DiskConfig(name: name, expiry: diskExpiry), transformer: TransformerFactory.forImage()) + let memory = MemoryStorage(config: MemoryConfig(expiry: memoryExpiry)) + let disk = try! DiskStorage(config: DiskConfig(name: name, expiry: diskExpiry), transformer: TransformerFactory.forData()) self.cache = .hybrid(HybridStorage(memoryStorage: memory, diskStorage: disk)) } - func get(_ url: URL, completion: ((UIImage?) -> Void)?) { + func get(_ url: URL, completion: ((Data?) -> Void)?) { let key = url.absoluteString if (try? cache.existsObject(forKey: key)) ?? false, - let image = try? cache.object(forKey: key) { - completion?(image) + let data = try? cache.object(forKey: key) { + completion?(data) } else { if let completion = completion, let request = requests[url] { request.callbacks.append(completion) @@ -53,7 +53,7 @@ class ImageCache { } } - func get(_ url: URL) -> UIImage? { + func get(_ url: URL) -> Data? { return try? cache.object(forKey: url.absoluteString) } @@ -64,9 +64,9 @@ class ImageCache { class Request { let url: URL var task: URLSessionDataTask? - var callbacks: [(UIImage?) -> Void] + var callbacks: [(Data?) -> Void] - init(url: URL, completion: ((UIImage?) -> Void)?) { + init(url: URL, completion: ((Data?) -> Void)?) { if let completion = completion { self.callbacks = [completion] } else { @@ -75,14 +75,14 @@ class ImageCache { self.url = url } - func run(cache: @escaping (UIImage) -> Void) { + func run(cache: @escaping (Data) -> Void) { task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in - guard error == nil, let data = data, let image = UIImage(data: data) else { + guard error == nil, let data = data else { self.complete(with: nil) return } - cache(image) - self.complete(with: image) + cache(data) + self.complete(with: data) }) task!.resume() } @@ -92,8 +92,8 @@ class ImageCache { complete(with: nil) } - func complete(with image: UIImage?) { - callbacks.forEach { $0(image) } + func complete(with data: Data?) { + callbacks.forEach { $0(data) } } } diff --git a/Tusker/Screens/Compose/ComposeViewController.swift b/Tusker/Screens/Compose/ComposeViewController.swift index 1fefe8a4..a11f9ae5 100644 --- a/Tusker/Screens/Compose/ComposeViewController.swift +++ b/Tusker/Screens/Compose/ComposeViewController.swift @@ -98,9 +98,10 @@ class ComposeViewController: UIViewController { inReplyToAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: inReplyToAvatarImageView) inReplyToAvatarImageView.layer.masksToBounds = true inReplyToAvatarImageView.image = nil - ImageCache.avatars.get(inReplyTo.account.avatar) { (image) in + ImageCache.avatars.get(inReplyTo.account.avatar) { (data) in + guard let data = data else { return } DispatchQueue.main.async { - self.inReplyToAvatarImageView.image = image + self.inReplyToAvatarImageView.image = UIImage(data: data) } } inReplyToLabel.text = "In reply to \(inReplyTo.account.realDisplayName)" diff --git a/Tusker/Views/AttachmentView.swift b/Tusker/Views/AttachmentView.swift index d85aa832..59133840 100644 --- a/Tusker/Views/AttachmentView.swift +++ b/Tusker/Views/AttachmentView.swift @@ -8,6 +8,7 @@ import UIKit import Pachyderm +import WebKit protocol AttachmentViewDelegate { func showLargeAttachment(for attachmentView: AttachmentView) @@ -43,9 +44,27 @@ class AttachmentView: UIImageView { } func loadImage() { - ImageCache.attachments.get(attachment.url) { (image) in - DispatchQueue.main.async { - self.image = image + ImageCache.attachments.get(attachment.url) { (data) in + guard let data = data else { + // TODO: error icon + return + } + + // TODO: better way of detecting gifs + if self.attachment.url.pathExtension == "gif" { + DispatchQueue.main.async { + // I hate this; this is awful + let webView = WKWebView(frame: self.bounds) + webView.isUserInteractionEnabled = false + webView.backgroundColor = .clear + webView.isOpaque = false + webView.load(data, mimeType: "image/gif", characterEncodingName: "utf-8", baseURL: self.attachment.url) + self.addSubview(webView) + } + } else { + DispatchQueue.main.async { + self.image = UIImage(data: data) + } } } } @@ -55,5 +74,5 @@ class AttachmentView: UIImageView { delegate?.showLargeAttachment(for: self) } } - + } diff --git a/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift index 5cf7dcdb..67591c1b 100644 --- a/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift @@ -79,17 +79,19 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive { usernameLabel.text = "@\(status.account.acct)" opAvatarImageView.image = nil opAvatarURL = status.account.avatar - ImageCache.avatars.get(status.account.avatar) { (image) in + ImageCache.avatars.get(status.account.avatar) { (data) in + guard let data = data else { return } DispatchQueue.main.async { - self.opAvatarImageView.image = image + self.opAvatarImageView.image = UIImage(data: data) self.opAvatarURL = nil } } actionAvatarImageView.image = nil actionAvatarURL = notification.account.avatar - ImageCache.avatars.get(notification.account.avatar) { (image) in + ImageCache.avatars.get(notification.account.avatar) { (data) in + guard let data = data else { return } DispatchQueue.main.async { - self.actionAvatarImageView.image = image + self.actionAvatarImageView.image = UIImage(data: data) self.actionAvatarURL = nil } } diff --git a/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift b/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift index fa08623f..7ca3e290 100644 --- a/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift @@ -51,9 +51,10 @@ class FollowNotificationTableViewCell: UITableViewCell, PreferencesAdaptive { usernameLabel.text = "@\(account.acct)" avatarImageView.image = nil avatarURL = account.avatar - ImageCache.avatars.get(account.avatar) { (image) in + ImageCache.avatars.get(account.avatar) { (data) in + guard let data = data else { return } DispatchQueue.main.async { - self.avatarImageView.image = image + self.avatarImageView.image = UIImage(data: data) self.avatarURL = nil } } diff --git a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift index 47fc7f9e..b6deb8f2 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift +++ b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift @@ -61,15 +61,17 @@ class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive { avatarImageView.image = nil avatarURL = account.avatar - ImageCache.avatars.get(account.avatar) { (image) in + ImageCache.avatars.get(account.avatar) { (data) in + guard let data = data else { return } DispatchQueue.main.async { - self.avatarImageView.image = image + self.avatarImageView.image = UIImage(data: data) self.avatarURL = nil } } - ImageCache.headers.get(account.header) { (image) in + ImageCache.headers.get(account.header) { (data) in + guard let data = data else { return } DispatchQueue.main.async { - self.headerImageView.image = image + self.headerImageView.image = UIImage(data: data) self.headerURL = nil } } diff --git a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift index d107ccfd..234adc20 100644 --- a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift +++ b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift @@ -80,9 +80,10 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive usernameLabel.text = "@\(account.acct)" avatarImageView.image = nil avatarURL = account.avatar - ImageCache.avatars.get(account.avatar) { (image) in + ImageCache.avatars.get(account.avatar) { (data) in + guard let data = data else { return } DispatchQueue.main.async { - self.avatarImageView.image = image + self.avatarImageView.image = UIImage(data: data) self.avatarURL = nil } } diff --git a/Tusker/Views/Status/StatusTableViewCell.swift b/Tusker/Views/Status/StatusTableViewCell.swift index 6b74eaad..4ed687de 100644 --- a/Tusker/Views/Status/StatusTableViewCell.swift +++ b/Tusker/Views/Status/StatusTableViewCell.swift @@ -97,10 +97,12 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive { usernameLabel.text = "@\(account.acct)" avatarImageView.image = nil avatarURL = account.avatar - ImageCache.avatars.get(account.avatar) { (image) in + ImageCache.avatars.get(account.avatar) { (data) in + self.avatarURL = nil + + guard let data = data else { return } DispatchQueue.main.async { - self.avatarImageView.image = image - self.avatarURL = nil + self.avatarImageView.image = UIImage(data: data) } } updateTimestamp()