diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 913d7c0b2..ee6c1dac9 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -164,8 +164,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(feedIconDidBecomeAvailable(_:)), name: .FeedIconDidBecomeAvailable, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(avatarDidBecomeAvailable(_:)), name: .AvatarDidBecomeAvailable, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(imageDidBecomeAvailable(_:)), name: .ImageDidBecomeAvailable, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(imageDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(accountDidDownloadArticles(_:)), name: .AccountDidDownloadArticles, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(accountStateDidChange(_:)), name: .AccountStateDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .AccountsDidChange, object: nil) @@ -475,7 +474,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr @objc func feedIconDidBecomeAvailable(_ note: Notification) { - guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed else { + guard showAvatars, let feed = note.userInfo?[UserInfoKey.feed] as? Feed else { return } let indexesToReload = tableView.indexesOfAvailableRowsPassingTest { (row) -> Bool in @@ -511,10 +510,19 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr } } - @objc func imageDidBecomeAvailable(_ note: Notification) { + @objc func faviconDidBecomeAvailable(_ note: Notification) { + guard showAvatars, let faviconURL = note.userInfo?[FaviconDownloader.UserInfoKey.faviconURL] as? String else { + return + } - if showAvatars { - queueReloadAvailableCells() + let indexesToReload = tableView.indexesOfAvailableRowsPassingTest { (row) -> Bool in + guard let article = articles.articleAtRow(row) else { + return false + } + return article.feed?.faviconURL == faviconURL + } + if let indexesToReload = indexesToReload { + reloadCells(for: indexesToReload) } } diff --git a/Shared/Images/FeedIconDownloader.swift b/Shared/Images/FeedIconDownloader.swift index 2fa08b0dc..001c884ad 100644 --- a/Shared/Images/FeedIconDownloader.swift +++ b/Shared/Images/FeedIconDownloader.swift @@ -25,10 +25,11 @@ public final class FeedIconDownloader { private var homePagesWithNoIconURL = Set() private var urlsInProgress = Set() private var cache = [Feed: RSImage]() + private var waitingForFeedURLs = [String: Feed]() init(imageDownloader: ImageDownloader) { - self.imageDownloader = imageDownloader + NotificationCenter.default.addObserver(self, selector: #selector(imageDidBecomeAvailable(_:)), name: .ImageDidBecomeAvailable, object: imageDownloader) } func resetCache() { @@ -45,7 +46,7 @@ public final class FeedIconDownloader { guard let homePageURL = feed.homePageURL else { return } - icon(forHomePageURL: homePageURL) { (image) in + icon(forHomePageURL: homePageURL, feed: feed) { (image) in if let image = image { self.postFeedIconDidBecomeAvailableNotification(feed) self.cache[feed] = image @@ -54,7 +55,7 @@ public final class FeedIconDownloader { } if let iconURL = feed.iconURL { - icon(forURL: iconURL) { (image) in + icon(forURL: iconURL, feed: feed) { (image) in if let image = image { self.postFeedIconDidBecomeAvailableNotification(feed) self.cache[feed] = image @@ -71,11 +72,20 @@ public final class FeedIconDownloader { return nil } + + @objc func imageDidBecomeAvailable(_ note: Notification) { + guard let url = note.userInfo?[UserInfoKey.url] as? String, let feed = waitingForFeedURLs[url] else { + return + } + waitingForFeedURLs[url] = nil + _ = icon(for: feed) + } + } private extension FeedIconDownloader { - func icon(forHomePageURL homePageURL: String, _ imageResultBlock: @escaping (RSImage?) -> Void) { + func icon(forHomePageURL homePageURL: String, feed: Feed, _ imageResultBlock: @escaping (RSImage?) -> Void) { if homePagesWithNoIconURL.contains(homePageURL) { imageResultBlock(nil) @@ -83,14 +93,15 @@ private extension FeedIconDownloader { } if let iconURL = cachedIconURL(for: homePageURL) { - icon(forURL: iconURL, imageResultBlock) + icon(forURL: iconURL, feed: feed, imageResultBlock) return } - findIconURLForHomePageURL(homePageURL) + findIconURLForHomePageURL(homePageURL, feed: feed) } - func icon(forURL url: String, _ imageResultBlock: @escaping (RSImage?) -> Void) { + func icon(forURL url: String, feed: Feed, _ imageResultBlock: @escaping (RSImage?) -> Void) { + waitingForFeedURLs[url] = feed guard let imageData = imageDownloader.image(for: url) else { imageResultBlock(nil) return @@ -117,7 +128,7 @@ private extension FeedIconDownloader { homePageToIconURLCache[homePageURL] = iconURL } - func findIconURLForHomePageURL(_ homePageURL: String) { + func findIconURLForHomePageURL(_ homePageURL: String, feed: Feed) { guard !urlsInProgress.contains(homePageURL) else { return @@ -130,15 +141,15 @@ private extension FeedIconDownloader { guard let metadata = metadata else { return } - self.pullIconURL(from: metadata, homePageURL: homePageURL) + self.pullIconURL(from: metadata, homePageURL: homePageURL, feed: feed) } } - func pullIconURL(from metadata: RSHTMLMetadata, homePageURL: String) { + func pullIconURL(from metadata: RSHTMLMetadata, homePageURL: String, feed: Feed) { if let url = metadata.bestWebsiteIconURL() { cacheIconURL(for: homePageURL, url) - icon(forURL: url) { (image) in + icon(forURL: url, feed: feed) { (image) in } return }