Create and use IconImageCache. It centralizes and de-dupes logic for getting feed/article images, and it caches the results, which helps performance.
This commit is contained in:
parent
28b00260e0
commit
9d2c8f000f
|
@ -146,18 +146,7 @@ private extension WebFeedInspectorViewController {
|
||||||
guard let feed = feed, let iconView = iconView else {
|
guard let feed = feed, let iconView = iconView else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
iconView.iconImage = IconImageCache.shared.imageForFeed(feed)
|
||||||
if let feedIcon = appDelegate.webFeedIconDownloader.icon(for: feed) {
|
|
||||||
iconView.iconImage = feedIcon
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let favicon = appDelegate.faviconDownloader.favicon(for: feed) {
|
|
||||||
iconView.iconImage = favicon
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
iconView.iconImage = feed.smallIcon
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateName() {
|
func updateName() {
|
||||||
|
|
|
@ -763,7 +763,7 @@ private extension SidebarViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageFor(_ node: Node) -> IconImage? {
|
func imageFor(_ node: Node) -> IconImage? {
|
||||||
if let feed = node.representedObject as? WebFeed, let feedIcon = appDelegate.webFeedIconDownloader.icon(for: feed) {
|
if let feed = node.representedObject as? WebFeed, let feedIcon = IconImageCache.shared.imageForFeed(feed) {
|
||||||
return feedIcon
|
return feedIcon
|
||||||
}
|
}
|
||||||
if let smallIconProvider = node.representedObject as? SmallIconProvider {
|
if let smallIconProvider = node.representedObject as? SmallIconProvider {
|
||||||
|
|
|
@ -886,28 +886,7 @@ extension TimelineViewController: NSTableViewDelegate {
|
||||||
if !showIcons {
|
if !showIcons {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return IconImageCache.shared.imageForArticle(article)
|
||||||
if let authors = article.authors {
|
|
||||||
for author in authors {
|
|
||||||
if let image = avatarForAuthor(author) {
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let feed = article.webFeed else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if let feedIcon = appDelegate.webFeedIconDownloader.icon(for: feed) {
|
|
||||||
return feedIcon
|
|
||||||
}
|
|
||||||
|
|
||||||
if let favicon = appDelegate.faviconDownloader.faviconAsIcon(for: feed) {
|
|
||||||
return favicon
|
|
||||||
}
|
|
||||||
|
|
||||||
return FaviconGenerator.favicon(feed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func avatarForAuthor(_ author: Author) -> IconImage? {
|
private func avatarForAuthor(_ author: Author) -> IconImage? {
|
||||||
|
|
|
@ -41,20 +41,6 @@ final class FeedIconImageLoader: ObservableObject {
|
||||||
private extension FeedIconImageLoader {
|
private extension FeedIconImageLoader {
|
||||||
|
|
||||||
func fetchImage() {
|
func fetchImage() {
|
||||||
if let webFeed = feed as? WebFeed {
|
image = IconImageCache.shared.imageForFeed(feed)
|
||||||
if let feedIconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed) {
|
|
||||||
image = feedIconImage
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) {
|
|
||||||
image = faviconImage
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let smallIconProvider = feed as? SmallIconProvider {
|
|
||||||
image = smallIconProvider.smallIcon
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1011,6 +1011,9 @@
|
||||||
844B5B691FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 844B5B681FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist */; };
|
844B5B691FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 844B5B681FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist */; };
|
||||||
845213231FCA5B11003B6E93 /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845213221FCA5B10003B6E93 /* ImageDownloader.swift */; };
|
845213231FCA5B11003B6E93 /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845213221FCA5B10003B6E93 /* ImageDownloader.swift */; };
|
||||||
845479881FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 845479871FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist */; };
|
845479881FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 845479871FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist */; };
|
||||||
|
8454C3F3263F2D8700E3F9C7 /* IconImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C3F2263F2D8700E3F9C7 /* IconImageCache.swift */; };
|
||||||
|
8454C3F8263F3AD400E3F9C7 /* IconImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C3F2263F2D8700E3F9C7 /* IconImageCache.swift */; };
|
||||||
|
8454C3FD263F3AD600E3F9C7 /* IconImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C3F2263F2D8700E3F9C7 /* IconImageCache.swift */; };
|
||||||
845A29091FC74B8E007B49E3 /* SingleFaviconDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29081FC74B8E007B49E3 /* SingleFaviconDownloader.swift */; };
|
845A29091FC74B8E007B49E3 /* SingleFaviconDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29081FC74B8E007B49E3 /* SingleFaviconDownloader.swift */; };
|
||||||
845A29221FC9251E007B49E3 /* SidebarCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29211FC9251E007B49E3 /* SidebarCellLayout.swift */; };
|
845A29221FC9251E007B49E3 /* SidebarCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29211FC9251E007B49E3 /* SidebarCellLayout.swift */; };
|
||||||
845A29241FC9255E007B49E3 /* SidebarCellAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29231FC9255E007B49E3 /* SidebarCellAppearance.swift */; };
|
845A29241FC9255E007B49E3 /* SidebarCellAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29231FC9255E007B49E3 /* SidebarCellAppearance.swift */; };
|
||||||
|
@ -1885,6 +1888,7 @@
|
||||||
844B5B681FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SidebarKeyboardShortcuts.plist; sourceTree = "<group>"; };
|
844B5B681FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SidebarKeyboardShortcuts.plist; sourceTree = "<group>"; };
|
||||||
845213221FCA5B10003B6E93 /* ImageDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageDownloader.swift; sourceTree = "<group>"; };
|
845213221FCA5B10003B6E93 /* ImageDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageDownloader.swift; sourceTree = "<group>"; };
|
||||||
845479871FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = TimelineKeyboardShortcuts.plist; sourceTree = "<group>"; };
|
845479871FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = TimelineKeyboardShortcuts.plist; sourceTree = "<group>"; };
|
||||||
|
8454C3F2263F2D8700E3F9C7 /* IconImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconImageCache.swift; sourceTree = "<group>"; };
|
||||||
845A29081FC74B8E007B49E3 /* SingleFaviconDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleFaviconDownloader.swift; sourceTree = "<group>"; };
|
845A29081FC74B8E007B49E3 /* SingleFaviconDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleFaviconDownloader.swift; sourceTree = "<group>"; };
|
||||||
845A29211FC9251E007B49E3 /* SidebarCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarCellLayout.swift; sourceTree = "<group>"; };
|
845A29211FC9251E007B49E3 /* SidebarCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarCellLayout.swift; sourceTree = "<group>"; };
|
||||||
845A29231FC9255E007B49E3 /* SidebarCellAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarCellAppearance.swift; sourceTree = "<group>"; };
|
845A29231FC9255E007B49E3 /* SidebarCellAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarCellAppearance.swift; sourceTree = "<group>"; };
|
||||||
|
@ -3418,6 +3422,7 @@
|
||||||
842E45CD1ED8C308000A8B52 /* AppNotifications.swift */,
|
842E45CD1ED8C308000A8B52 /* AppNotifications.swift */,
|
||||||
51C4CFEF24D37D1F00AF9874 /* Secrets.swift */,
|
51C4CFEF24D37D1F00AF9874 /* Secrets.swift */,
|
||||||
511B9805237DCAC90028BCAA /* UserInfoKey.swift */,
|
511B9805237DCAC90028BCAA /* UserInfoKey.swift */,
|
||||||
|
8454C3F2263F2D8700E3F9C7 /* IconImageCache.swift */,
|
||||||
51C452AD2265102800C03939 /* Timeline */,
|
51C452AD2265102800C03939 /* Timeline */,
|
||||||
84702AB31FA27AE8006B8943 /* Commands */,
|
84702AB31FA27AE8006B8943 /* Commands */,
|
||||||
51934CCC231078DC006127BE /* Activity */,
|
51934CCC231078DC006127BE /* Activity */,
|
||||||
|
@ -5127,6 +5132,7 @@
|
||||||
65ED4007235DEF6C0081F399 /* AddFeedController.swift in Sources */,
|
65ED4007235DEF6C0081F399 /* AddFeedController.swift in Sources */,
|
||||||
65ED4008235DEF6C0081F399 /* AccountRefreshTimer.swift in Sources */,
|
65ED4008235DEF6C0081F399 /* AccountRefreshTimer.swift in Sources */,
|
||||||
65ED4009235DEF6C0081F399 /* SidebarStatusBarView.swift in Sources */,
|
65ED4009235DEF6C0081F399 /* SidebarStatusBarView.swift in Sources */,
|
||||||
|
8454C3FD263F3AD600E3F9C7 /* IconImageCache.swift in Sources */,
|
||||||
65ED400A235DEF6C0081F399 /* SearchTimelineFeedDelegate.swift in Sources */,
|
65ED400A235DEF6C0081F399 /* SearchTimelineFeedDelegate.swift in Sources */,
|
||||||
65ED400B235DEF6C0081F399 /* TodayFeedDelegate.swift in Sources */,
|
65ED400B235DEF6C0081F399 /* TodayFeedDelegate.swift in Sources */,
|
||||||
65ED400C235DEF6C0081F399 /* FolderInspectorViewController.swift in Sources */,
|
65ED400C235DEF6C0081F399 /* FolderInspectorViewController.swift in Sources */,
|
||||||
|
@ -5352,6 +5358,7 @@
|
||||||
516AE9B32371C372007DEEAA /* MasterFeedTableViewSectionHeaderLayout.swift in Sources */,
|
516AE9B32371C372007DEEAA /* MasterFeedTableViewSectionHeaderLayout.swift in Sources */,
|
||||||
51DC370B2405BC9A0095D371 /* PreloadedWebView.swift in Sources */,
|
51DC370B2405BC9A0095D371 /* PreloadedWebView.swift in Sources */,
|
||||||
D3555BF524664566005E48C3 /* ArticleSearchBar.swift in Sources */,
|
D3555BF524664566005E48C3 /* ArticleSearchBar.swift in Sources */,
|
||||||
|
8454C3F3263F2D8700E3F9C7 /* IconImageCache.swift in Sources */,
|
||||||
B24E9ADE245AB88400DA5718 /* NSAttributedString+NetNewsWire.swift in Sources */,
|
B24E9ADE245AB88400DA5718 /* NSAttributedString+NetNewsWire.swift in Sources */,
|
||||||
C5A6ED5223C9AF4300AB6BE2 /* TitleActivityItemSource.swift in Sources */,
|
C5A6ED5223C9AF4300AB6BE2 /* TitleActivityItemSource.swift in Sources */,
|
||||||
51DC37092402F1470095D371 /* MasterFeedDataSourceOperation.swift in Sources */,
|
51DC37092402F1470095D371 /* MasterFeedDataSourceOperation.swift in Sources */,
|
||||||
|
@ -5522,6 +5529,7 @@
|
||||||
849A97771ED9EC04007D329B /* TimelineCellData.swift in Sources */,
|
849A97771ED9EC04007D329B /* TimelineCellData.swift in Sources */,
|
||||||
841ABA6020145EC100980E11 /* BuiltinSmartFeedInspectorViewController.swift in Sources */,
|
841ABA6020145EC100980E11 /* BuiltinSmartFeedInspectorViewController.swift in Sources */,
|
||||||
D5E4CC54202C1361009B4FFC /* AppDelegate+Scriptability.swift in Sources */,
|
D5E4CC54202C1361009B4FFC /* AppDelegate+Scriptability.swift in Sources */,
|
||||||
|
8454C3F8263F3AD400E3F9C7 /* IconImageCache.swift in Sources */,
|
||||||
518651B223555EB20078E021 /* NNW3Document.swift in Sources */,
|
518651B223555EB20078E021 /* NNW3Document.swift in Sources */,
|
||||||
D5F4EDB5200744A700B9E363 /* ScriptingObject.swift in Sources */,
|
D5F4EDB5200744A700B9E363 /* ScriptingObject.swift in Sources */,
|
||||||
D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */,
|
D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */,
|
||||||
|
|
|
@ -248,12 +248,11 @@ private extension ActivityManager {
|
||||||
attributeSet.title = feed.nameForDisplay
|
attributeSet.title = feed.nameForDisplay
|
||||||
attributeSet.keywords = makeKeywords(feed.nameForDisplay)
|
attributeSet.keywords = makeKeywords(feed.nameForDisplay)
|
||||||
attributeSet.relatedUniqueIdentifier = ActivityManager.identifer(for: feed)
|
attributeSet.relatedUniqueIdentifier = ActivityManager.identifer(for: feed)
|
||||||
if let iconImage = appDelegate.webFeedIconDownloader.icon(for: feed) {
|
|
||||||
attributeSet.thumbnailData = iconImage.image.dataRepresentation()
|
if let iconImage = IconImageCache.shared.imageForFeed(feed) {
|
||||||
} else if let iconImage = appDelegate.faviconDownloader.faviconAsIcon(for: feed) {
|
|
||||||
attributeSet.thumbnailData = iconImage.image.dataRepresentation()
|
attributeSet.thumbnailData = iconImage.image.dataRepresentation()
|
||||||
}
|
}
|
||||||
|
|
||||||
selectingActivity!.contentAttributeSet = attributeSet
|
selectingActivity!.contentAttributeSet = attributeSet
|
||||||
selectingActivity!.needsSave = true
|
selectingActivity!.needsSave = true
|
||||||
|
|
||||||
|
|
|
@ -96,32 +96,7 @@ extension Article {
|
||||||
}
|
}
|
||||||
|
|
||||||
func iconImage() -> IconImage? {
|
func iconImage() -> IconImage? {
|
||||||
if let authors = authors, authors.count == 1, let author = authors.first {
|
return IconImageCache.shared.imageForArticle(self)
|
||||||
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let authors = webFeed?.authors, authors.count == 1, let author = authors.first {
|
|
||||||
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let webFeed = webFeed else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let feedIconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed)
|
|
||||||
if feedIconImage != nil {
|
|
||||||
return feedIconImage
|
|
||||||
}
|
|
||||||
|
|
||||||
if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) {
|
|
||||||
return faviconImage
|
|
||||||
}
|
|
||||||
|
|
||||||
return FaviconGenerator.favicon(webFeed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func iconImageUrl(webFeed: WebFeed) -> URL? {
|
func iconImageUrl(webFeed: WebFeed) -> URL? {
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
//
|
||||||
|
// IconImageCache.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Brent Simmons on 5/2/21.
|
||||||
|
// Copyright © 2021 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Account
|
||||||
|
import Articles
|
||||||
|
|
||||||
|
class IconImageCache {
|
||||||
|
|
||||||
|
static var shared = IconImageCache()
|
||||||
|
|
||||||
|
private var smartFeedIconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
private var webFeedIconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
private var faviconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
private var smallIconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
private var authorIconImageCache = [Author: IconImage]()
|
||||||
|
|
||||||
|
func imageFor(_ feedID: FeedIdentifier) -> IconImage? {
|
||||||
|
if let smartFeed = SmartFeedsController.shared.find(by: feedID) {
|
||||||
|
return imageForFeed(smartFeed)
|
||||||
|
}
|
||||||
|
if let feed = AccountManager.shared.existingFeed(with: feedID) {
|
||||||
|
return imageForFeed(feed)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageForFeed(_ feed: Feed) -> IconImage? {
|
||||||
|
guard let feedID = feed.feedID else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if let smartFeed = feed as? PseudoFeed {
|
||||||
|
return imageForSmartFeed(smartFeed, feedID)
|
||||||
|
}
|
||||||
|
if let webFeed = feed as? WebFeed, let iconImage = imageForWebFeed(webFeed, feedID) {
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
if let smallIconProvider = feed as? SmallIconProvider {
|
||||||
|
return imageForSmallIconProvider(smallIconProvider, feedID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageForArticle(_ article: Article) -> IconImage? {
|
||||||
|
if let iconImage = imageForAuthors(article.authors) {
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
guard let feed = article.webFeed else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return imageForFeed(feed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func emptyCache() {
|
||||||
|
smartFeedIconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
webFeedIconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
faviconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
smallIconImageCache = [FeedIdentifier: IconImage]()
|
||||||
|
authorIconImageCache = [Author: IconImage]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension IconImageCache {
|
||||||
|
|
||||||
|
func imageForSmartFeed(_ smartFeed: PseudoFeed, _ feedID: FeedIdentifier) -> IconImage? {
|
||||||
|
if let iconImage = smartFeedIconImageCache[feedID] {
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
if let iconImage = smartFeed.smallIcon {
|
||||||
|
smartFeedIconImageCache[feedID] = iconImage
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageForWebFeed(_ webFeed: WebFeed, _ feedID: FeedIdentifier) -> IconImage? {
|
||||||
|
if let iconImage = webFeedIconImageCache[feedID] {
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
if let iconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed) {
|
||||||
|
webFeedIconImageCache[feedID] = iconImage
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
if let faviconImage = faviconImageCache[feedID] {
|
||||||
|
return faviconImage
|
||||||
|
}
|
||||||
|
if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) {
|
||||||
|
faviconImageCache[feedID] = faviconImage
|
||||||
|
return faviconImage
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageForSmallIconProvider(_ provider: SmallIconProvider, _ feedID: FeedIdentifier) -> IconImage? {
|
||||||
|
if let iconImage = smallIconImageCache[feedID] {
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
if let iconImage = provider.smallIcon {
|
||||||
|
smallIconImageCache[feedID] = iconImage
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageForAuthors(_ authors: Set<Author>?) -> IconImage? {
|
||||||
|
guard let authors = authors, authors.count == 1, let author = authors.first else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return imageForAuthor(author)
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageForAuthor(_ author: Author) -> IconImage? {
|
||||||
|
if let iconImage = authorIconImageCache[author] {
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
if let iconImage = appDelegate.authorAvatarDownloader.image(for: author) {
|
||||||
|
authorIconImageCache[author] = iconImage
|
||||||
|
return iconImage
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -132,6 +132,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||||
func applicationWillTerminate(_ application: UIApplication) {
|
func applicationWillTerminate(_ application: UIApplication) {
|
||||||
shuttingDown = true
|
shuttingDown = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||||
|
IconImageCache.shared.emptyCache()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Notifications
|
// MARK: Notifications
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,8 @@ class WebFeedInspectorViewController: UITableViewController {
|
||||||
@IBOutlet weak var feedURLLabel: InteractiveLabel!
|
@IBOutlet weak var feedURLLabel: InteractiveLabel!
|
||||||
|
|
||||||
private var headerView: InspectorIconHeaderView?
|
private var headerView: InspectorIconHeaderView?
|
||||||
private var iconImage: IconImage {
|
private var iconImage: IconImage? {
|
||||||
if let feedIcon = appDelegate.webFeedIconDownloader.icon(for: webFeed) {
|
return IconImageCache.shared.imageForFeed(webFeed)
|
||||||
return feedIcon
|
|
||||||
}
|
|
||||||
if let favicon = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) {
|
|
||||||
return favicon
|
|
||||||
}
|
|
||||||
return FaviconGenerator.favicon(webFeed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private let homePageIndexPath = IndexPath(row: 0, section: 1)
|
private let homePageIndexPath = IndexPath(row: 0, section: 1)
|
||||||
|
|
|
@ -42,11 +42,6 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private var smartFeedIconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
private var webFeedIconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
private var faviconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
private var smallIconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
|
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
@ -91,12 +86,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||||
// Empty IconImage caches
|
IconImageCache.shared.emptyCache()
|
||||||
smartFeedIconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
webFeedIconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
faviconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
smallIconImageCache = [FeedIdentifier: IconImage]()
|
|
||||||
|
|
||||||
super.traitCollectionDidChange(previousTraitCollection)
|
super.traitCollectionDidChange(previousTraitCollection)
|
||||||
reloadAllVisibleCells()
|
reloadAllVisibleCells()
|
||||||
}
|
}
|
||||||
|
@ -858,69 +848,12 @@ private extension MasterFeedViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureIcon(_ cell: MasterFeedTableViewCell, _ identifier: MasterFeedTableViewIdentifier) {
|
func configureIcon(_ cell: MasterFeedTableViewCell, _ identifier: MasterFeedTableViewIdentifier) {
|
||||||
cell.iconImage = imageFor(identifier)
|
guard let feedID = identifier.feedID else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cell.iconImage = IconImageCache.shared.imageFor(feedID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageFor(_ identifier: MasterFeedTableViewIdentifier) -> IconImage? {
|
|
||||||
guard let feedID = identifier.feedID else { return nil }
|
|
||||||
|
|
||||||
if let smartFeed = SmartFeedsController.shared.find(by: feedID) {
|
|
||||||
return imageForSmartFeed(smartFeed, feedID)
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let feed = AccountManager.shared.existingFeed(with: feedID) else { return nil }
|
|
||||||
|
|
||||||
if let webFeed = feed as? WebFeed, let iconImage = imageForWebFeed(webFeed, feedID) {
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
|
|
||||||
if let smallIconProvider = feed as? SmallIconProvider, let iconImage = imageForSmallIconProvider(smallIconProvider, feedID) {
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func imageForSmartFeed(_ smartFeed: PseudoFeed, _ feedID: FeedIdentifier) -> IconImage? {
|
|
||||||
if let iconImage = smartFeedIconImageCache[feedID] {
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
if let iconImage = smartFeed.smallIcon {
|
|
||||||
smartFeedIconImageCache[feedID] = iconImage
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func imageForWebFeed(_ webFeed: WebFeed, _ feedID: FeedIdentifier) -> IconImage? {
|
|
||||||
if let iconImage = webFeedIconImageCache[feedID] {
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
if let iconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed) {
|
|
||||||
webFeedIconImageCache[feedID] = iconImage
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
if let faviconImage = faviconImageCache[feedID] {
|
|
||||||
return faviconImage
|
|
||||||
}
|
|
||||||
if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) {
|
|
||||||
faviconImageCache[feedID] = faviconImage
|
|
||||||
return faviconImage
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func imageForSmallIconProvider(_ provider: SmallIconProvider, _ feedID: FeedIdentifier) -> IconImage? {
|
|
||||||
if let iconImage = smallIconImageCache[feedID] {
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
if let iconImage = provider.smallIcon {
|
|
||||||
smallIconImageCache[feedID] = iconImage
|
|
||||||
return iconImage
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func nameFor(_ node: Node) -> String {
|
func nameFor(_ node: Node) -> String {
|
||||||
if let displayNameProvider = node.representedObject as? DisplayNameProvider {
|
if let displayNameProvider = node.representedObject as? DisplayNameProvider {
|
||||||
return displayNameProvider.nameForDisplay
|
return displayNameProvider.nameForDisplay
|
||||||
|
|
|
@ -146,22 +146,12 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||||
|
|
||||||
// At some point we should refactor the current Feed IndexPath out and only use the timeline feed
|
// At some point we should refactor the current Feed IndexPath out and only use the timeline feed
|
||||||
private(set) var currentFeedIndexPath: IndexPath?
|
private(set) var currentFeedIndexPath: IndexPath?
|
||||||
|
|
||||||
var timelineIconImage: IconImage? {
|
var timelineIconImage: IconImage? {
|
||||||
if let feed = timelineFeed as? WebFeed {
|
guard let timelineFeed = timelineFeed else {
|
||||||
|
return nil
|
||||||
let feedIconImage = appDelegate.webFeedIconDownloader.icon(for: feed)
|
|
||||||
if feedIconImage != nil {
|
|
||||||
return feedIconImage
|
|
||||||
}
|
|
||||||
|
|
||||||
if let faviconIconImage = appDelegate.faviconDownloader.faviconAsIcon(for: feed) {
|
|
||||||
return faviconIconImage
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return IconImageCache.shared.imageForFeed(timelineFeed)
|
||||||
return (timelineFeed as? SmallIconProvider)?.smallIcon
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var exceptionArticleFetcher: ArticleFetcher?
|
private var exceptionArticleFetcher: ArticleFetcher?
|
||||||
|
|
Loading…
Reference in New Issue