Show GIFs in AttachmentView
This commit is contained in:
parent
86d064dc6e
commit
9249a4aeaa
|
@ -15,31 +15,31 @@ class ImageCache {
|
||||||
static let headers = ImageCache(name: "Headers", memoryExpiry: .seconds(60 * 60), diskExpiry: .seconds(60 * 60 * 24))
|
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))
|
static let attachments = ImageCache(name: "Attachments", memoryExpiry: .seconds(60 * 2))
|
||||||
|
|
||||||
let cache: Cache<UIImage>
|
let cache: Cache<Data>
|
||||||
|
|
||||||
var requests = [URL: Request]()
|
var requests = [URL: Request]()
|
||||||
|
|
||||||
init(name: String, memoryExpiry expiry: Expiry) {
|
init(name: String, memoryExpiry expiry: Expiry) {
|
||||||
let storage = MemoryStorage<UIImage>(config: MemoryConfig(expiry: expiry))
|
let storage = MemoryStorage<Data>(config: MemoryConfig(expiry: expiry))
|
||||||
self.cache = .memory(storage)
|
self.cache = .memory(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(name: String, diskExpiry expiry: Expiry) {
|
init(name: String, diskExpiry expiry: Expiry) {
|
||||||
let storage = try! DiskStorage<UIImage>(config: DiskConfig(name: name, expiry: expiry), transformer: TransformerFactory.forImage())
|
let storage = try! DiskStorage<Data>(config: DiskConfig(name: name, expiry: expiry), transformer: TransformerFactory.forData())
|
||||||
self.cache = .disk(storage)
|
self.cache = .disk(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(name: String, memoryExpiry: Expiry, diskExpiry: Expiry) {
|
init(name: String, memoryExpiry: Expiry, diskExpiry: Expiry) {
|
||||||
let memory = MemoryStorage<UIImage>(config: MemoryConfig(expiry: memoryExpiry))
|
let memory = MemoryStorage<Data>(config: MemoryConfig(expiry: memoryExpiry))
|
||||||
let disk = try! DiskStorage<UIImage>(config: DiskConfig(name: name, expiry: diskExpiry), transformer: TransformerFactory.forImage())
|
let disk = try! DiskStorage<Data>(config: DiskConfig(name: name, expiry: diskExpiry), transformer: TransformerFactory.forData())
|
||||||
self.cache = .hybrid(HybridStorage(memoryStorage: memory, diskStorage: disk))
|
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
|
let key = url.absoluteString
|
||||||
if (try? cache.existsObject(forKey: key)) ?? false,
|
if (try? cache.existsObject(forKey: key)) ?? false,
|
||||||
let image = try? cache.object(forKey: key) {
|
let data = try? cache.object(forKey: key) {
|
||||||
completion?(image)
|
completion?(data)
|
||||||
} else {
|
} else {
|
||||||
if let completion = completion, let request = requests[url] {
|
if let completion = completion, let request = requests[url] {
|
||||||
request.callbacks.append(completion)
|
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)
|
return try? cache.object(forKey: url.absoluteString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,9 +64,9 @@ class ImageCache {
|
||||||
class Request {
|
class Request {
|
||||||
let url: URL
|
let url: URL
|
||||||
var task: URLSessionDataTask?
|
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 {
|
if let completion = completion {
|
||||||
self.callbacks = [completion]
|
self.callbacks = [completion]
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,14 +75,14 @@ class ImageCache {
|
||||||
self.url = url
|
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
|
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)
|
self.complete(with: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cache(image)
|
cache(data)
|
||||||
self.complete(with: image)
|
self.complete(with: data)
|
||||||
})
|
})
|
||||||
task!.resume()
|
task!.resume()
|
||||||
}
|
}
|
||||||
|
@ -92,8 +92,8 @@ class ImageCache {
|
||||||
complete(with: nil)
|
complete(with: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func complete(with image: UIImage?) {
|
func complete(with data: Data?) {
|
||||||
callbacks.forEach { $0(image) }
|
callbacks.forEach { $0(data) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,9 +98,10 @@ class ComposeViewController: UIViewController {
|
||||||
inReplyToAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: inReplyToAvatarImageView)
|
inReplyToAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: inReplyToAvatarImageView)
|
||||||
inReplyToAvatarImageView.layer.masksToBounds = true
|
inReplyToAvatarImageView.layer.masksToBounds = true
|
||||||
inReplyToAvatarImageView.image = nil
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.inReplyToAvatarImageView.image = image
|
self.inReplyToAvatarImageView.image = UIImage(data: data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inReplyToLabel.text = "In reply to \(inReplyTo.account.realDisplayName)"
|
inReplyToLabel.text = "In reply to \(inReplyTo.account.realDisplayName)"
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
import WebKit
|
||||||
|
|
||||||
protocol AttachmentViewDelegate {
|
protocol AttachmentViewDelegate {
|
||||||
func showLargeAttachment(for attachmentView: AttachmentView)
|
func showLargeAttachment(for attachmentView: AttachmentView)
|
||||||
|
@ -43,9 +44,27 @@ class AttachmentView: UIImageView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadImage() {
|
func loadImage() {
|
||||||
ImageCache.attachments.get(attachment.url) { (image) in
|
ImageCache.attachments.get(attachment.url) { (data) in
|
||||||
DispatchQueue.main.async {
|
guard let data = data else {
|
||||||
self.image = image
|
// 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)
|
delegate?.showLargeAttachment(for: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,17 +79,19 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
usernameLabel.text = "@\(status.account.acct)"
|
usernameLabel.text = "@\(status.account.acct)"
|
||||||
opAvatarImageView.image = nil
|
opAvatarImageView.image = nil
|
||||||
opAvatarURL = status.account.avatar
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.opAvatarImageView.image = image
|
self.opAvatarImageView.image = UIImage(data: data)
|
||||||
self.opAvatarURL = nil
|
self.opAvatarURL = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actionAvatarImageView.image = nil
|
actionAvatarImageView.image = nil
|
||||||
actionAvatarURL = notification.account.avatar
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.actionAvatarImageView.image = image
|
self.actionAvatarImageView.image = UIImage(data: data)
|
||||||
self.actionAvatarURL = nil
|
self.actionAvatarURL = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,10 @@ class FollowNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
usernameLabel.text = "@\(account.acct)"
|
usernameLabel.text = "@\(account.acct)"
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = UIImage(data: data)
|
||||||
self.avatarURL = nil
|
self.avatarURL = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,15 +61,17 @@ class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
|
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = UIImage(data: data)
|
||||||
self.avatarURL = nil
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.headerImageView.image = image
|
self.headerImageView.image = UIImage(data: data)
|
||||||
self.headerURL = nil
|
self.headerURL = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,9 +80,10 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
usernameLabel.text = "@\(account.acct)"
|
usernameLabel.text = "@\(account.acct)"
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = UIImage(data: data)
|
||||||
self.avatarURL = nil
|
self.avatarURL = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,10 +97,12 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
usernameLabel.text = "@\(account.acct)"
|
usernameLabel.text = "@\(account.acct)"
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
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 {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = UIImage(data: data)
|
||||||
self.avatarURL = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateTimestamp()
|
updateTimestamp()
|
||||||
|
|
Loading…
Reference in New Issue