diff --git a/Account/Sources/Account/AccountManager.swift b/Account/Sources/Account/AccountManager.swift index 496bb5f3d..8e36be0e1 100644 --- a/Account/Sources/Account/AccountManager.swift +++ b/Account/Sources/Account/AccountManager.swift @@ -370,7 +370,35 @@ public final class AccountManager: UnreadCountProvider { return false } - + + public func anyLocalOriCloudAccountHasAtLeastOneRedditAPIFeed() -> Bool { + // We removed our Reddit code, and the ability to read feeds from Reddit, + // when Reddit announced the end of the free tier for the Reddit API. + // We are cheering on Reddit’s increasing irrelevancy. + + for account in accounts { + if account.type == .cloudKit || account.type == .onMyMac { + for webfeed in account.flattenedWebFeeds() { + if feedRequiresRedditAPI(webfeed) { + return true + } + } + } + } + + return false + } + + /// Return true if a feed is for reddit.com and the path doesn’t end with .rss. + /// + /// More info: [Pathogen-David's Guide to RSS and Reddit!](https://www.reddit.com/r/pathogendavid/comments/tv8m9/pathogendavids_guide_to_rss_and_reddit/) + private func feedRequiresRedditAPI(_ feed: WebFeed) -> Bool { + if let components = URLComponents(string: webfeed.url), let host = components.host { + return host.hasSuffix("reddit.com") && !path.hasSuffix(".rss") + } + return false + } + // MARK: - Fetching Articles // These fetch articles from active accounts and return a merged Set
. diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index 691bd1538..f365d022b 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -132,6 +132,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(didWakeNotification(_:)), name: NSWorkspace.didWakeNotification, object: nil) appDelegate = self + + if shouldShowTwitterDeprecationAlert() { + showTwitterDeprecationAlert() + } + else if shouldShowRedditDeprecationAlert() { + showRedditDeprecationAlert() + } } // MARK: - API @@ -666,7 +673,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, @IBAction func showHelp(_ sender: Any?) { - Browser.open("https://netnewswire.com/help/mac/6.0/en/", inBackground: false) + Browser.open("https://netnewswire.com/help/mac/6.1/en/", inBackground: false) } @IBAction func donateToAppCampForGirls(_ sender: Any?) { @@ -822,7 +829,7 @@ internal extension AppDelegate { } let websiteText = NSMutableAttributedString() - websiteText.append(NSAttributedString(string: NSLocalizedString("Author's Website", comment: "Author's Website"), attributes: attrs)) + websiteText.append(NSAttributedString(string: NSLocalizedString("Author‘s website:", comment: "Author's Website"), attributes: attrs)) if #available(macOS 11.0, *) { websiteText.append(NSAttributedString(string: "\n")) @@ -951,7 +958,61 @@ internal extension AppDelegate { alert.runModal() } } - + + private func shouldShowTwitterDeprecationAlert() -> Bool { + if AppDefaults.shared.twitterDeprecationAlertShown { return false } + + let expiryDate = Date(timeIntervalSince1970: 1691539200) // August 9th 2023, 00:00 UTC + let currentDate = Date() + if currentDate > expiryDate { + return false // If after August 9th, don't show + } + + return AccountManager.shared.anyLocalOriCloudAccountHasAtLeastOneTwitterFeed() + } + + private func showTwitterDeprecationAlert() { + assert(shouldShowTwitterDeprecationAlert()) + + AppDefaults.shared.twitterDeprecationAlertShown = true + DispatchQueue.main.async { + let alert = NSAlert() + alert.alertStyle = .warning + alert.messageText = NSLocalizedString("Twitter Integration Removed", comment: "Twitter Integration Removed") + alert.informativeText = NSLocalizedString("Twitter has ended free access to the parts of the Twitter API that we need.\n\nSince Twitter does not provide RSS feeds, we’ve had to use the Twitter API. Without free access to that API, we can’t read feeds from Twitter.\n\nWe’ve left your Twitter feeds intact. If you have any starred items from those feeds, they will remain as long as you don’t delete those feeds.\n\nYou can still read whatever you have already downloaded. However, those feeds will no longer update.", comment: "Twitter deprecation informative text.") + alert.addButton(withTitle: NSLocalizedString("OK", comment: "OK")) + alert.buttons[0].keyEquivalent = "\r" + alert.runModal() + } + } + + private func shouldShowRedditDeprecationAlert() -> Bool { + if AppDefaults.shared.redditDeprecationAlertShown { return false } + + let expiryDate = Date(timeIntervalSince1970: 1701331200) // Thu Nov 30 2023 00:00:00 GMT-0800 (Pacific Standard Time) + let currentDate = Date() + if currentDate > expiryDate { + return false + } + + return AccountManager.shared.anyLocalOriCloudAccountHasAtLeastOneRedditAPIFeed() + } + + private func showRedditDeprecationAlert() { + assert(shouldShowRedditDeprecationAlert()) + AppDefaults.shared.redditDeprecationAlertShown = true + + DispatchQueue.main.async { + let alert = NSAlert() + alert.alertStyle = .warning + alert.messageText = NSLocalizedString("Reddit API Integration Removed", comment: "Reddit API Integration Removed") + alert.informativeText = NSLocalizedString("Reddit has ended free access to their API.\n\nThough Reddit does provide RSS feeds, we used the Reddit API to get more and better data. But, without free access to that API, we have had to stop using it.\n\nWe’ve left your Reddit feeds intact. If you have any starred items from those feeds, they will remain as long as you don’t delete those feeds.\n\nYou can still read whatever you have already downloaded.\n\nAlso, importantly — Reddit still provides RSS feeds, and you can follow Reddit activity through RSS.", comment: "Reddit deprecation message") + alert.addButton(withTitle: NSLocalizedString("OK", comment: "OK")) + alert.buttons[0].keyEquivalent = "\r" + alert.runModal() + } + } + @objc func openThemesFolder(_ sender: Any) { if themeImportPath == nil { let url = URL(fileURLWithPath: ArticleThemesManager.shared.folderPath)