diff --git a/Evergreen/Images/AuthorAvatarDownloader.swift b/Evergreen/Images/AuthorAvatarDownloader.swift index 2678de30e..8965a0457 100644 --- a/Evergreen/Images/AuthorAvatarDownloader.swift +++ b/Evergreen/Images/AuthorAvatarDownloader.swift @@ -11,17 +11,19 @@ import Data extension Notification.Name { - static let AvatarDidBecomeAvailable = Notification.Name("AvatarDidBecomeAvailableNotification") // UserInfoKey.author + static let AvatarDidBecomeAvailable = Notification.Name("AvatarDidBecomeAvailableNotification") // UserInfoKey.imageURL (which is an avatarURL) } final class AuthorAvatarDownloader { private let imageDownloader: ImageDownloader private var cache = [String: NSImage]() // avatarURL: NSImage + private var waitingForAvatarURLs = Set() init(imageDownloader: ImageDownloader) { self.imageDownloader = imageDownloader + NotificationCenter.default.addObserver(self, selector: #selector(imageDidBecomeAvailable(_:)), name: .ImageDidBecomeAvailable, object: imageDownloader) } func image(for author: Author) -> NSImage? { @@ -33,21 +35,49 @@ final class AuthorAvatarDownloader { return cachedImage } if let image = imageDownloader.image(for: avatarURL) { - cache[avatarURL] = image - postAvatarDidBecomeAvailableNotification(author) + handleImageDidBecomeAvailable(avatarURL, image) return image } + else { + waitingForAvatarURLs.insert(avatarURL) + } + return nil } + + @objc func imageDidBecomeAvailable(_ note: Notification) { + + guard let avatarURL = note.userInfo?[UserInfoKey.url] as? String else { + return + } + guard waitingForAvatarURLs.contains(avatarURL) else { + return + } + guard let image = imageDownloader.image(for: avatarURL) else { + return + } + + handleImageDidBecomeAvailable(avatarURL, image) + } } private extension AuthorAvatarDownloader { - func postAvatarDidBecomeAvailableNotification(_ author: Author) { + func handleImageDidBecomeAvailable(_ avatarURL: String, _ image: NSImage) { + + if cache[avatarURL] == nil { + cache[avatarURL] = image + } + if waitingForAvatarURLs.contains(avatarURL) { + waitingForAvatarURLs.remove(avatarURL) + postAvatarDidBecomeAvailableNotification(avatarURL) + } + } + + func postAvatarDidBecomeAvailableNotification(_ avatarURL: String) { DispatchQueue.main.async { - let userInfo: [AnyHashable: Any] = [UserInfoKey.author: author] - NotificationCenter.default.post(name: .AvatarDidBecomeAvailable, object: self, userInfo: userInfo) + NotificationCenter.default.post(name: .AvatarDidBecomeAvailable, object: self, userInfo: [UserInfoKey.url: avatarURL]) } } } diff --git a/Evergreen/Images/ImageDownloader.swift b/Evergreen/Images/ImageDownloader.swift index 3f079178e..7d819a539 100644 --- a/Evergreen/Images/ImageDownloader.swift +++ b/Evergreen/Images/ImageDownloader.swift @@ -12,7 +12,7 @@ import RSWeb extension Notification.Name { - static let ImageDidBecomeAvailable = Notification.Name("ImageDidBecomeAvailableNotification") // ImageDownloader.UserInfoKey.imageURL + static let ImageDidBecomeAvailable = Notification.Name("ImageDidBecomeAvailableNotification") // UserInfoKey.url } final class ImageDownloader { @@ -24,10 +24,6 @@ final class ImageDownloader { private var urlsInProgress = Set() private var badURLs = Set() // That return a 404 or whatever. Just skip them in the future. - struct UserInfoKey { - static let imageURL = "imageURL" - } - init(folder: String) { self.folder = folder @@ -135,6 +131,6 @@ private extension ImageDownloader { func postImageDidBecomeAvailableNotification(_ url: String) { - NotificationCenter.default.post(name: .ImageDidBecomeAvailable, object: self, userInfo: [UserInfoKey.imageURL: url]) + NotificationCenter.default.post(name: .ImageDidBecomeAvailable, object: self, userInfo: [UserInfoKey.url: url]) } } diff --git a/Evergreen/MainWindow/Timeline/TimelineViewController.swift b/Evergreen/MainWindow/Timeline/TimelineViewController.swift index ba87e906a..0f9f1342b 100644 --- a/Evergreen/MainWindow/Timeline/TimelineViewController.swift +++ b/Evergreen/MainWindow/Timeline/TimelineViewController.swift @@ -327,7 +327,7 @@ class TimelineViewController: NSViewController, UndoableCommandRunner { @objc func avatarDidBecomeAvailable(_ note: Notification) { - guard let author = note.userInfo?[UserInfoKey.author] as? Author, let avatarURL = author.avatarURL else { + guard let avatarURL = note.userInfo?[UserInfoKey.url] as? String else { return } let articlesToReload = articles.filter { (article) -> Bool in