forked from shadowfacts/Tusker
Merge branch 'image-caching'
This commit is contained in:
commit
b796f288c8
|
@ -1,3 +1,6 @@
|
||||||
[submodule "SwiftSoup"]
|
[submodule "SwiftSoup"]
|
||||||
path = SwiftSoup
|
path = SwiftSoup
|
||||||
url = git://github.com/scinfu/SwiftSoup.git
|
url = git://github.com/scinfu/SwiftSoup.git
|
||||||
|
[submodule "Cache"]
|
||||||
|
path = Cache
|
||||||
|
url = git@github.com:hyperoslo/Cache.git
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 8c42c575cf28b2ff0e780c9728721e9a8891c92e
|
|
@ -12,8 +12,10 @@
|
||||||
04496BD0216252E5001F1B23 /* TTTAttributedLabel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 04496BC8216252E5001F1B23 /* TTTAttributedLabel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
04496BD0216252E5001F1B23 /* TTTAttributedLabel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 04496BC8216252E5001F1B23 /* TTTAttributedLabel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
04496BD52162530A001F1B23 /* TTTAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 04496BD42162530A001F1B23 /* TTTAttributedLabel.m */; };
|
04496BD52162530A001F1B23 /* TTTAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 04496BD42162530A001F1B23 /* TTTAttributedLabel.m */; };
|
||||||
04496BD721625361001F1B23 /* ContentLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04496BD621625361001F1B23 /* ContentLabel.swift */; };
|
04496BD721625361001F1B23 /* ContentLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04496BD621625361001F1B23 /* ContentLabel.swift */; };
|
||||||
|
0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; };
|
||||||
|
0461A3912163CBAE00C0A807 /* Cache.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */; };
|
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */; };
|
||||||
04DACE8E212CC7CC009840C4 /* AvatarCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8D212CC7CC009840C4 /* AvatarCache.swift */; };
|
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8D212CC7CC009840C4 /* ImageCache.swift */; };
|
||||||
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED00B021481ED800567C53 /* SteppedProgressView.swift */; };
|
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED00B021481ED800567C53 /* SteppedProgressView.swift */; };
|
||||||
D6028B9B2150811100F223B9 /* MastodonCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6028B9A2150811100F223B9 /* MastodonCache.swift */; };
|
D6028B9B2150811100F223B9 /* MastodonCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6028B9A2150811100F223B9 /* MastodonCache.swift */; };
|
||||||
D61099B42144B0CC00432DC2 /* Pachyderm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D61099AB2144B0CC00432DC2 /* Pachyderm.framework */; };
|
D61099B42144B0CC00432DC2 /* Pachyderm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D61099AB2144B0CC00432DC2 /* Pachyderm.framework */; };
|
||||||
|
@ -181,6 +183,7 @@
|
||||||
04496BD0216252E5001F1B23 /* TTTAttributedLabel.framework in Embed Frameworks */,
|
04496BD0216252E5001F1B23 /* TTTAttributedLabel.framework in Embed Frameworks */,
|
||||||
D61099C12144B0CC00432DC2 /* Pachyderm.framework in Embed Frameworks */,
|
D61099C12144B0CC00432DC2 /* Pachyderm.framework in Embed Frameworks */,
|
||||||
D6BED170212663DA00F02DA0 /* SwiftSoup.framework in Embed Frameworks */,
|
D6BED170212663DA00F02DA0 /* SwiftSoup.framework in Embed Frameworks */,
|
||||||
|
0461A3912163CBAE00C0A807 /* Cache.framework in Embed Frameworks */,
|
||||||
);
|
);
|
||||||
name = "Embed Frameworks";
|
name = "Embed Frameworks";
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -193,8 +196,9 @@
|
||||||
04496BCB216252E5001F1B23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
04496BCB216252E5001F1B23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
04496BD42162530A001F1B23 /* TTTAttributedLabel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TTTAttributedLabel.m; sourceTree = "<group>"; };
|
04496BD42162530A001F1B23 /* TTTAttributedLabel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TTTAttributedLabel.m; sourceTree = "<group>"; };
|
||||||
04496BD621625361001F1B23 /* ContentLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLabel.swift; sourceTree = "<group>"; };
|
04496BD621625361001F1B23 /* ContentLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLabel.swift; sourceTree = "<group>"; };
|
||||||
|
0461A38F2163CBAE00C0A807 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = "<group>"; };
|
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = "<group>"; };
|
||||||
04DACE8D212CC7CC009840C4 /* AvatarCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarCache.swift; sourceTree = "<group>"; };
|
04DACE8D212CC7CC009840C4 /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
|
||||||
04ED00B021481ED800567C53 /* SteppedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SteppedProgressView.swift; sourceTree = "<group>"; };
|
04ED00B021481ED800567C53 /* SteppedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SteppedProgressView.swift; sourceTree = "<group>"; };
|
||||||
D6028B9A2150811100F223B9 /* MastodonCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonCache.swift; sourceTree = "<group>"; };
|
D6028B9A2150811100F223B9 /* MastodonCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonCache.swift; sourceTree = "<group>"; };
|
||||||
D61099AB2144B0CC00432DC2 /* Pachyderm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pachyderm.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D61099AB2144B0CC00432DC2 /* Pachyderm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pachyderm.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -343,6 +347,7 @@
|
||||||
04496BCF216252E5001F1B23 /* TTTAttributedLabel.framework in Frameworks */,
|
04496BCF216252E5001F1B23 /* TTTAttributedLabel.framework in Frameworks */,
|
||||||
D61099C02144B0CC00432DC2 /* Pachyderm.framework in Frameworks */,
|
D61099C02144B0CC00432DC2 /* Pachyderm.framework in Frameworks */,
|
||||||
D65A37F321472F300087646E /* SwiftSoup.framework in Frameworks */,
|
D65A37F321472F300087646E /* SwiftSoup.framework in Frameworks */,
|
||||||
|
0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -684,6 +689,7 @@
|
||||||
D6D4DDC3212518A000E1C4BB = {
|
D6D4DDC3212518A000E1C4BB = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0461A38F2163CBAE00C0A807 /* Cache.framework */,
|
||||||
D6BED16E212663DA00F02DA0 /* SwiftSoup.framework */,
|
D6BED16E212663DA00F02DA0 /* SwiftSoup.framework */,
|
||||||
D61099AC2144B0CC00432DC2 /* Pachyderm */,
|
D61099AC2144B0CC00432DC2 /* Pachyderm */,
|
||||||
D61099B92144B0CC00432DC2 /* PachydermTests */,
|
D61099B92144B0CC00432DC2 /* PachydermTests */,
|
||||||
|
@ -714,7 +720,7 @@
|
||||||
children = (
|
children = (
|
||||||
D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */,
|
D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */,
|
||||||
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
||||||
04DACE8D212CC7CC009840C4 /* AvatarCache.swift */,
|
04DACE8D212CC7CC009840C4 /* ImageCache.swift */,
|
||||||
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
||||||
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
||||||
D6757A7A2157E00100721E32 /* XCallbackURL */,
|
D6757A7A2157E00100721E32 /* XCallbackURL */,
|
||||||
|
@ -1082,7 +1088,7 @@
|
||||||
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
|
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
|
||||||
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
||||||
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
||||||
04DACE8E212CC7CC009840C4 /* AvatarCache.swift in Sources */,
|
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */,
|
||||||
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */,
|
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */,
|
||||||
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */,
|
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */,
|
||||||
D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */,
|
D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */,
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "container:Tusker.xcodeproj">
|
location = "container:Tusker.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Cache/Cache.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:SwiftSoup/SwiftSoup.xcodeproj">
|
location = "group:SwiftSoup/SwiftSoup.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// ImageCache.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfactson 8/21/18.
|
|
||||||
// Copyright © 2018 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
class AvatarCache {
|
|
||||||
|
|
||||||
static let shared = AvatarCache()
|
|
||||||
|
|
||||||
let cache = NSCache<NSString, UIImage>()
|
|
||||||
|
|
||||||
var requests = [URL: URLSessionDataTask]()
|
|
||||||
var requestCallbacks = [URL: [(UIImage?) -> Void]]()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func get(_ url: URL, completion: @escaping (UIImage?) -> Void) {
|
|
||||||
let key = url.absoluteString as NSString
|
|
||||||
if let image = cache.object(forKey: key) {
|
|
||||||
completion(image)
|
|
||||||
} else if var callbacks = requestCallbacks[url] {
|
|
||||||
callbacks.append(completion)
|
|
||||||
requestCallbacks[url] = callbacks
|
|
||||||
} else {
|
|
||||||
requestCallbacks[url] = [completion]
|
|
||||||
let task = URLSession.shared.dataTask(with: url) { data, response, error in
|
|
||||||
guard error == nil, let data = data, let image = UIImage(data: data) else {
|
|
||||||
let callbacks = self.requestCallbacks.removeValue(forKey: url)
|
|
||||||
callbacks?.forEach({ callback in
|
|
||||||
// todo: default avatar for failed requests
|
|
||||||
callback(nil)
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let callbacks = self.requestCallbacks.removeValue(forKey: url)
|
|
||||||
callbacks?.forEach({ callback in
|
|
||||||
callback(image)
|
|
||||||
})
|
|
||||||
self.cache.setObject(image, forKey: key)
|
|
||||||
}
|
|
||||||
task.resume()
|
|
||||||
requests[url] = task
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cancel(_ url: URL) {
|
|
||||||
requests[url]?.cancel()
|
|
||||||
requests.removeValue(forKey: url)
|
|
||||||
requestCallbacks.removeValue(forKey: url)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
//
|
||||||
|
// ImageCache.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 8/21/18.
|
||||||
|
// Copyright © 2018 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Cache
|
||||||
|
|
||||||
|
class ImageCache {
|
||||||
|
|
||||||
|
static let avatars = ImageCache(name: "Avatars")
|
||||||
|
static let headers = ImageCache(name: "Headers")
|
||||||
|
static let attachments = ImageCache(name: "Attachments", diskExpiry: .seconds(60 * 60), memoryExpiry: .seconds(60))
|
||||||
|
|
||||||
|
let storage: Storage<UIImage>
|
||||||
|
|
||||||
|
var requests = [URL: Request]()
|
||||||
|
|
||||||
|
init(name: String, diskExpiry: Expiry = .seconds(60 * 60 * 24), memoryExpiry: Expiry = .seconds(60 * 60)) {
|
||||||
|
self.storage = try! Storage(
|
||||||
|
diskConfig: DiskConfig(name: name, expiry: diskExpiry),
|
||||||
|
memoryConfig: MemoryConfig(expiry: memoryExpiry),
|
||||||
|
transformer: TransformerFactory.forImage())
|
||||||
|
}
|
||||||
|
|
||||||
|
func get(_ url: URL, completion: ((UIImage?) -> Void)?) {
|
||||||
|
let key = url.absoluteString
|
||||||
|
if (try? storage.existsObject(forKey: key)) ?? false,
|
||||||
|
let image = try? storage.object(forKey: key) {
|
||||||
|
completion?(image)
|
||||||
|
} else {
|
||||||
|
if let completion = completion, let request = requests[url] {
|
||||||
|
request.callbacks.append(completion)
|
||||||
|
} else {
|
||||||
|
let request = Request(url: url, completion: completion)
|
||||||
|
requests[url] = request
|
||||||
|
request.run { (image) in
|
||||||
|
try? self.storage.setObject(image, forKey: key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancel(_ url: URL) {
|
||||||
|
requests[url]?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
let url: URL
|
||||||
|
var task: URLSessionDataTask?
|
||||||
|
var callbacks: [(UIImage?) -> Void]
|
||||||
|
|
||||||
|
init(url: URL, completion: ((UIImage?) -> Void)?) {
|
||||||
|
if let completion = completion {
|
||||||
|
self.callbacks = [completion]
|
||||||
|
} else {
|
||||||
|
self.callbacks = []
|
||||||
|
}
|
||||||
|
self.url = url
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(cache: @escaping (UIImage) -> Void) {
|
||||||
|
task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
|
||||||
|
guard error == nil, let data = data, let image = UIImage(data: data) else {
|
||||||
|
self.complete(with: nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cache(image)
|
||||||
|
self.complete(with: image)
|
||||||
|
})
|
||||||
|
task!.resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancel() {
|
||||||
|
task?.cancel()
|
||||||
|
complete(with: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func complete(with image: UIImage?) {
|
||||||
|
callbacks.forEach { $0(image) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -92,7 +92,7 @@ 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
|
||||||
AvatarCache.shared.get(inReplyTo.account.avatar) { image in
|
ImageCache.avatars.get(inReplyTo.account.avatar) { (image) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.inReplyToAvatarImageView.image = image
|
self.inReplyToAvatarImageView.image = image
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ class AttachmentView: UIImageView {
|
||||||
|
|
||||||
var attachment: Attachment!
|
var attachment: Attachment!
|
||||||
|
|
||||||
var task: URLSessionDataTask?
|
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
super.init(coder: aDecoder)
|
super.init(coder: aDecoder)
|
||||||
commonInit()
|
commonInit()
|
||||||
|
@ -45,13 +43,11 @@ class AttachmentView: UIImageView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadImage() {
|
func loadImage() {
|
||||||
task = URLSession.shared.dataTask(with: attachment.url) { data, response, error in
|
ImageCache.attachments.get(attachment.url) { (image) in
|
||||||
guard error == nil, let data = data, let image = UIImage(data: data) else { return }
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.image = image
|
self.image = image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task!.resume()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func imagePressed() {
|
@objc func imagePressed() {
|
||||||
|
|
|
@ -75,7 +75,7 @@ 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
|
||||||
AvatarCache.shared.get(status.account.avatar) { image in
|
ImageCache.avatars.get(status.account.avatar) { (image) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.opAvatarImageView.image = image
|
self.opAvatarImageView.image = image
|
||||||
self.opAvatarURL = nil
|
self.opAvatarURL = nil
|
||||||
|
@ -83,7 +83,7 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
}
|
}
|
||||||
actionAvatarImageView.image = nil
|
actionAvatarImageView.image = nil
|
||||||
actionAvatarURL = notification.account.avatar
|
actionAvatarURL = notification.account.avatar
|
||||||
AvatarCache.shared.get(notification.account.avatar) { image in
|
ImageCache.avatars.get(notification.account.avatar) { (image) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.actionAvatarImageView.image = image
|
self.actionAvatarImageView.image = image
|
||||||
self.actionAvatarURL = nil
|
self.actionAvatarURL = nil
|
||||||
|
@ -158,10 +158,10 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
|
|
||||||
override func prepareForReuse() {
|
override func prepareForReuse() {
|
||||||
if let url = opAvatarURL {
|
if let url = opAvatarURL {
|
||||||
AvatarCache.shared.cancel(url)
|
ImageCache.avatars.cancel(url)
|
||||||
}
|
}
|
||||||
if let url = actionAvatarURL {
|
if let url = actionAvatarURL {
|
||||||
AvatarCache.shared.cancel(url)
|
ImageCache.avatars.cancel(url)
|
||||||
}
|
}
|
||||||
updateTimestampWorkItem?.cancel()
|
updateTimestampWorkItem?.cancel()
|
||||||
updateTimestampWorkItem = nil
|
updateTimestampWorkItem = nil
|
||||||
|
|
|
@ -49,7 +49,7 @@ class FollowNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
usernameLabel.text = "@\(account.acct)"
|
usernameLabel.text = "@\(account.acct)"
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
avatarURL = account.avatar
|
||||||
AvatarCache.shared.get(account.avatar) { image in
|
ImageCache.avatars.get(account.avatar) { (image) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = image
|
||||||
self.avatarURL = nil
|
self.avatarURL = nil
|
||||||
|
@ -81,7 +81,7 @@ class FollowNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
|
|
||||||
override func prepareForReuse() {
|
override func prepareForReuse() {
|
||||||
if let url = avatarURL {
|
if let url = avatarURL {
|
||||||
AvatarCache.shared.cancel(url)
|
ImageCache.avatars.cancel(url)
|
||||||
}
|
}
|
||||||
updateTimestampWorkItem?.cancel()
|
updateTimestampWorkItem?.cancel()
|
||||||
updateTimestampWorkItem = nil
|
updateTimestampWorkItem = nil
|
||||||
|
|
|
@ -28,8 +28,7 @@ class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
var accountID: String!
|
var accountID: String!
|
||||||
|
|
||||||
var avatarURL: URL?
|
var avatarURL: URL?
|
||||||
|
var headerURL: URL?
|
||||||
var headerImageDownloadTask: URLSessionDataTask?
|
|
||||||
|
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
avatarContainerView.layer.masksToBounds = true
|
avatarContainerView.layer.masksToBounds = true
|
||||||
|
@ -59,20 +58,18 @@ class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
|
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
avatarURL = account.avatar
|
||||||
AvatarCache.shared.get(account.avatar) { image in
|
ImageCache.avatars.get(account.avatar) { (image) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = image
|
||||||
self.avatarURL = nil
|
self.avatarURL = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headerImageDownloadTask = URLSession.shared.dataTask(with: account.header) { data, response, error in
|
ImageCache.headers.get(account.header) { (image) in
|
||||||
guard error == nil, let data = data, let image = UIImage(data: data) else { return }
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.headerImageView.image = image
|
self.headerImageView.image = image
|
||||||
self.headerImageDownloadTask = nil
|
self.headerURL = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headerImageDownloadTask!.resume()
|
|
||||||
|
|
||||||
noteLabel.setTextFromHtml(account.note)
|
noteLabel.setTextFromHtml(account.note)
|
||||||
|
|
||||||
|
@ -92,7 +89,10 @@ class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
|
|
||||||
override func prepareForReuse() {
|
override func prepareForReuse() {
|
||||||
if let url = avatarURL {
|
if let url = avatarURL {
|
||||||
AvatarCache.shared.cancel(url)
|
ImageCache.avatars.cancel(url)
|
||||||
|
}
|
||||||
|
if let url = headerURL {
|
||||||
|
ImageCache.headers.cancel(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
usernameLabel.text = "@\(account.acct)"
|
usernameLabel.text = "@\(account.acct)"
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
avatarURL = account.avatar
|
||||||
AvatarCache.shared.get(account.avatar) { image in
|
ImageCache.avatars.get(account.avatar) { (image) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = image
|
||||||
self.avatarURL = nil
|
self.avatarURL = nil
|
||||||
|
@ -85,7 +85,6 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
}
|
}
|
||||||
updateTimestamp()
|
updateTimestamp()
|
||||||
|
|
||||||
attachmentsView.subviews.forEach { $0.removeFromSuperview() }
|
|
||||||
let attachments = status.attachments.filter({ $0.kind == .image })
|
let attachments = status.attachments.filter({ $0.kind == .image })
|
||||||
if attachments.count > 0 {
|
if attachments.count > 0 {
|
||||||
attachmentsView.isHidden = false
|
attachmentsView.isHidden = false
|
||||||
|
@ -151,13 +150,11 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
|
|
||||||
override func prepareForReuse() {
|
override func prepareForReuse() {
|
||||||
if let url = avatarURL {
|
if let url = avatarURL {
|
||||||
AvatarCache.shared.cancel(url)
|
ImageCache.avatars.cancel(url)
|
||||||
}
|
}
|
||||||
updateTimestampWorkItem?.cancel()
|
updateTimestampWorkItem?.cancel()
|
||||||
updateTimestampWorkItem = nil
|
updateTimestampWorkItem = nil
|
||||||
attachmentsView.subviews.forEach { view in
|
attachmentsView.subviews.forEach { $0.removeFromSuperview() }
|
||||||
(view as? AttachmentView)?.task?.cancel()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func accountPressed() {
|
@objc func accountPressed() {
|
||||||
|
|
|
@ -92,7 +92,7 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
usernameLabel.text = "@\(account.acct)"
|
usernameLabel.text = "@\(account.acct)"
|
||||||
avatarImageView.image = nil
|
avatarImageView.image = nil
|
||||||
avatarURL = account.avatar
|
avatarURL = account.avatar
|
||||||
AvatarCache.shared.get(account.avatar) { image in
|
ImageCache.avatars.get(account.avatar) { (image) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.avatarImageView.image = image
|
self.avatarImageView.image = image
|
||||||
self.avatarURL = nil
|
self.avatarURL = nil
|
||||||
|
@ -166,14 +166,11 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
|
|
||||||
override func prepareForReuse() {
|
override func prepareForReuse() {
|
||||||
if let url = avatarURL {
|
if let url = avatarURL {
|
||||||
AvatarCache.shared.cancel(url)
|
ImageCache.avatars.cancel(url)
|
||||||
}
|
}
|
||||||
updateTimestampWorkItem?.cancel()
|
updateTimestampWorkItem?.cancel()
|
||||||
updateTimestampWorkItem = nil
|
updateTimestampWorkItem = nil
|
||||||
attachmentsView.subviews.forEach { view in
|
attachmentsView.subviews.forEach { $0.removeFromSuperview() }
|
||||||
(view as? AttachmentView)?.task?.cancel()
|
|
||||||
view.removeFromSuperview()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||||
|
|
Loading…
Reference in New Issue