diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index a0cf01842..a02505a21 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -39,9 +39,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, var userNotificationManager: UserNotificationManager! var faviconDownloader: FaviconDownloader! - var imageDownloader: ImageDownloader! - var authorAvatarDownloader: AuthorAvatarDownloader! - var webFeedIconDownloader: FeedIconDownloader! var extensionContainersFile: ExtensionContainersFile! var extensionFeedAddRequestFile: ExtensionFeedAddRequestFile! @@ -169,10 +166,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, let imagesFolder = (cacheFolder as NSString).appendingPathComponent("Images") let imagesFolderURL = URL(fileURLWithPath: imagesFolder) try! FileManager.default.createDirectory(at: imagesFolderURL, withIntermediateDirectories: true, attributes: nil) - imageDownloader = ImageDownloader(folder: imagesFolder) - - authorAvatarDownloader = AuthorAvatarDownloader(imageDownloader: imageDownloader) - webFeedIconDownloader = FeedIconDownloader(imageDownloader: imageDownloader, folder: cacheFolder) appName = (Bundle.main.infoDictionary!["CFBundleExecutable"]! as! String) } diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 9677b47f5..02afa0ae7 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -890,7 +890,7 @@ extension TimelineViewController: NSTableViewDelegate { } private func avatarForAuthor(_ author: Author) -> IconImage? { - return appDelegate.authorAvatarDownloader.image(for: author) + return AuthorAvatarDownloader.shared.image(for: author) } private func makeTimelineCellEmpty(_ cell: TimelineTableCellView) { diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 2de9592fb..ad67c0ccc 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -1038,7 +1038,6 @@ 841ABA5F20145EC100980E11 /* BuiltinSmartFeedInspectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuiltinSmartFeedInspectorViewController.swift; sourceTree = ""; }; 84216D0222128B9D0049B9B9 /* DetailWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailWebViewController.swift; sourceTree = ""; }; 842611891FCB67AA0086A189 /* FeedIconDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedIconDownloader.swift; sourceTree = ""; }; - 8426119F1FCB72600086A189 /* FeaturedImageDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturedImageDownloader.swift; sourceTree = ""; }; 842611A11FCB769D0086A189 /* RSHTMLMetadata+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSHTMLMetadata+Extension.swift"; sourceTree = ""; }; 842E45CD1ED8C308000A8B52 /* AppNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppNotifications.swift; sourceTree = ""; }; 842E45DC1ED8C54B000A8B52 /* Browser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Browser.swift; sourceTree = ""; }; @@ -1826,7 +1825,6 @@ 845213221FCA5B10003B6E93 /* ImageDownloader.swift */, 84E850851FCB60CE0072EA88 /* AuthorAvatarDownloader.swift */, 842611891FCB67AA0086A189 /* FeedIconDownloader.swift */, - 8426119F1FCB72600086A189 /* FeaturedImageDownloader.swift */, 842611A11FCB769D0086A189 /* RSHTMLMetadata+Extension.swift */, ); path = Images; diff --git a/Shared/IconImageCache.swift b/Shared/IconImageCache.swift index 1a7bc1826..7722f382f 100644 --- a/Shared/IconImageCache.swift +++ b/Shared/IconImageCache.swift @@ -84,7 +84,7 @@ private extension IconImageCache { if let iconImage = webFeedIconImageCache[feedID] { return iconImage } - if let iconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed) { + if let iconImage = FeedIconDownloader.shared.icon(for: webFeed) { webFeedIconImageCache[feedID] = iconImage return iconImage } @@ -120,7 +120,7 @@ private extension IconImageCache { if let iconImage = authorIconImageCache[author] { return iconImage } - if let iconImage = appDelegate.authorAvatarDownloader.image(for: author) { + if let iconImage = AuthorAvatarDownloader.shared.image(for: author) { authorIconImageCache[author] = iconImage return iconImage } diff --git a/Shared/Images/AuthorAvatarDownloader.swift b/Shared/Images/AuthorAvatarDownloader.swift index c69077c0d..471325d05 100644 --- a/Shared/Images/AuthorAvatarDownloader.swift +++ b/Shared/Images/AuthorAvatarDownloader.swift @@ -17,13 +17,14 @@ extension Notification.Name { final class AuthorAvatarDownloader { - private let imageDownloader: ImageDownloader + public static let shared = AuthorAvatarDownloader() + + private let imageDownloader = ImageDownloader.shared private var cache = [String: IconImage]() // avatarURL: RSImage private var waitingForAvatarURLs = Set() - init(imageDownloader: ImageDownloader) { + init() { - self.imageDownloader = imageDownloader NotificationCenter.default.addObserver(self, selector: #selector(imageDidBecomeAvailable(_:)), name: .ImageDidBecomeAvailable, object: imageDownloader) } diff --git a/Shared/Images/ImageDownloader.swift b/Shared/Images/ImageDownloader.swift index d5eb2f0b2..9df7d399a 100644 --- a/Shared/Images/ImageDownloader.swift +++ b/Shared/Images/ImageDownloader.swift @@ -10,6 +10,7 @@ import Foundation import os.log import RSCore import RSWeb +import Core extension Notification.Name { @@ -18,20 +19,21 @@ extension Notification.Name { final class ImageDownloader { + public static let shared = ImageDownloader() + private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "ImageDownloader") - private let folder: String private var diskCache: BinaryDiskCache private let queue: DispatchQueue private var imageCache = [String: Data]() // url: image private var urlsInProgress = Set() private var badURLs = Set() // That return a 404 or whatever. Just skip them in the future. - init(folder: String) { + init() { - self.folder = folder - self.diskCache = BinaryDiskCache(folder: folder) - self.queue = DispatchQueue(label: "ImageDownloader serial queue - \(folder)") + let folder = AppConfig.cacheSubfolder(named: "Images") + self.diskCache = BinaryDiskCache(folder: folder.path) + self.queue = DispatchQueue(label: "ImageDownloader serial queue - \(folder.path)") } @discardableResult diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index fd83e9b0d..054c19b62 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -41,8 +41,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD var userNotificationManager: UserNotificationManager! var faviconDownloader: FaviconDownloader! var imageDownloader: ImageDownloader! - var authorAvatarDownloader: AuthorAvatarDownloader! - var webFeedIconDownloader: FeedIconDownloader! var extensionContainersFile: ExtensionContainersFile! var extensionFeedAddRequestFile: ExtensionFeedAddRequestFile! var widgetDataEncoder: WidgetDataEncoder! @@ -230,24 +228,15 @@ private extension AppDelegate { let tempDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! let faviconsFolderURL = tempDir.appendingPathComponent("Favicons") let imagesFolderURL = tempDir.appendingPathComponent("Images") - + try! FileManager.default.createDirectory(at: faviconsFolderURL, withIntermediateDirectories: true, attributes: nil) let faviconsFolder = faviconsFolderURL.absoluteString let faviconsFolderPath = faviconsFolder.suffix(from: faviconsFolder.index(faviconsFolder.startIndex, offsetBy: 7)) faviconDownloader = FaviconDownloader(folder: String(faviconsFolderPath)) - - let imagesFolder = imagesFolderURL.absoluteString - let imagesFolderPath = imagesFolder.suffix(from: imagesFolder.index(imagesFolder.startIndex, offsetBy: 7)) + try! FileManager.default.createDirectory(at: imagesFolderURL, withIntermediateDirectories: true, attributes: nil) - imageDownloader = ImageDownloader(folder: String(imagesFolderPath)) - - authorAvatarDownloader = AuthorAvatarDownloader(imageDownloader: imageDownloader) - - let tempFolder = tempDir.absoluteString - let tempFolderPath = tempFolder.suffix(from: tempFolder.index(tempFolder.startIndex, offsetBy: 7)) - webFeedIconDownloader = FeedIconDownloader(imageDownloader: imageDownloader, folder: String(tempFolderPath)) } - + private func initializeHomeScreenQuickActions() { let unreadTitle = NSLocalizedString("First Unread", comment: "First Unread") let unreadIcon = UIApplicationShortcutIcon(systemImageName: "chevron.down.circle")