diff --git a/Account/Sources/Account/AccountManager.swift b/Account/Sources/Account/AccountManager.swift
index 0989691cc..abdf4d154 100644
--- a/Account/Sources/Account/AccountManager.swift
+++ b/Account/Sources/Account/AccountManager.swift
@@ -246,7 +246,7 @@ public final class AccountManager: UnreadCountProvider {
}
}
- public func refreshAll(errorHandler: @escaping (Error) -> Void, completion: (() -> Void)? = nil) {
+ public func refreshAll(errorHandler: @escaping @MainActor (Error) -> Void, completion: (() -> Void)? = nil) {
guard let reachability = try? Reachability(hostname: "apple.com"), reachability.connection != .unavailable else { return }
let group = DispatchGroup()
@@ -259,7 +259,9 @@ public final class AccountManager: UnreadCountProvider {
case .success:
break
case .failure(let error):
- errorHandler(error)
+ Task { @MainActor in
+ errorHandler(error)
+ }
}
}
}
diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift
index 44dc42137..16ec251f3 100644
--- a/Mac/AppDelegate.swift
+++ b/Mac/AppDelegate.swift
@@ -110,7 +110,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
private var crashReporter: PLCrashReporter!
#endif
- override init() {
+ @MainActor override init() {
NSWindow.allowsAutomaticWindowTabbing = false
super.init()
@@ -136,19 +136,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
// MARK: - API
- func showAddFolderSheetOnWindow(_ window: NSWindow) {
+ @MainActor func showAddFolderSheetOnWindow(_ window: NSWindow) {
addFolderWindowController = AddFolderWindowController()
addFolderWindowController!.runSheetOnWindow(window)
}
- func showAddWebFeedSheetOnWindow(_ window: NSWindow, urlString: String?, name: String?, account: Account?, folder: Folder?) {
+ @MainActor func showAddWebFeedSheetOnWindow(_ window: NSWindow, urlString: String?, name: String?, account: Account?, folder: Folder?) {
addFeedController = AddFeedController(hostWindow: window)
addFeedController?.showAddFeedSheet(.webFeed, urlString, name, account, folder)
}
// MARK: - NSApplicationDelegate
- func applicationWillFinishLaunching(_ notification: Notification) {
+ @MainActor func applicationWillFinishLaunching(_ notification: Notification) {
installAppleEventHandlers()
CacheCleaner.purgeIfNecessary()
@@ -179,7 +179,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
appName = (Bundle.main.infoDictionary!["CFBundleExecutable"]! as! String)
}
- func applicationDidFinishLaunching(_ note: Notification) {
+ @MainActor func applicationDidFinishLaunching(_ note: Notification) {
#if MAC_APP_STORE || TEST
checkForUpdatesMenuItem.isHidden = true
@@ -292,7 +292,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
- func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([NSUserActivityRestoring]) -> Void) -> Bool {
+ @MainActor func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([NSUserActivityRestoring]) -> Void) -> Bool {
guard let mainWindowController = mainWindowController else {
return false
}
@@ -300,7 +300,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
return true
}
- func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
+ @MainActor func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
// https://github.com/brentsimmons/NetNewsWire/issues/522
// I couldn’t reproduce the crashing bug, but it appears to happen on creating a main window
// and its views and view controllers. The check below is so that the app does nothing
@@ -314,26 +314,26 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
return false
}
- func applicationDidBecomeActive(_ notification: Notification) {
+ @MainActor func applicationDidBecomeActive(_ notification: Notification) {
fireOldTimers()
}
- func applicationDidResignActive(_ notification: Notification) {
+ @MainActor func applicationDidResignActive(_ notification: Notification) {
ArticleStringFormatter.emptyCaches()
saveState()
}
- func application(_ application: NSApplication, didReceiveRemoteNotification userInfo: [String : Any]) {
+ @MainActor func application(_ application: NSApplication, didReceiveRemoteNotification userInfo: [String : Any]) {
AccountManager.shared.receiveRemoteNotification(userInfo: userInfo)
}
- func application(_ sender: NSApplication, openFile filename: String) -> Bool {
+ @MainActor func application(_ sender: NSApplication, openFile filename: String) -> Bool {
guard filename.hasSuffix(ArticleTheme.nnwThemeSuffix) else { return false }
importTheme(filename: filename)
return true
}
- func applicationWillTerminate(_ notification: Notification) {
+ @MainActor func applicationWillTerminate(_ notification: Notification) {
shuttingDown = true
saveState()
@@ -347,7 +347,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
while !isShutDownSyncDone && RunLoop.current.run(mode: .default, before: timeout) && timeout > Date() { }
}
- func presentThemeImportError(_ error: Error) {
+ @MainActor func presentThemeImportError(_ error: Error) {
var informativeText: String = ""
if let decodingError = error as? DecodingError {
@@ -386,19 +386,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
alert.buttons[0].keyEquivalent = "\r"
- let response = alert.runModal()
+ _ = alert.runModal()
}
}
// MARK: Notifications
- @objc func unreadCountDidChange(_ note: Notification) {
+ @MainActor @objc func unreadCountDidChange(_ note: Notification) {
if note.object is AccountManager {
unreadCount = AccountManager.shared.unreadCount
}
}
- @objc func webFeedSettingDidChange(_ note: Notification) {
+ @MainActor @objc func webFeedSettingDidChange(_ note: Notification) {
guard let feed = note.object as? WebFeed, let key = note.userInfo?[WebFeed.WebFeedSettingUserInfoKey] as? String else {
return
}
@@ -407,14 +407,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
}
- @objc func inspectableObjectsDidChange(_ note: Notification) {
+ @MainActor @objc func inspectableObjectsDidChange(_ note: Notification) {
guard let inspectorWindowController = inspectorWindowController, inspectorWindowController.isOpen else {
return
}
inspectorWindowController.objects = objectsForInspector()
}
- @objc func userDefaultsDidChange(_ note: Notification) {
+ @MainActor @objc func userDefaultsDidChange(_ note: Notification) {
updateSortMenuItems()
updateGroupByFeedMenuItem()
@@ -426,11 +426,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
updateDockBadge()
}
- @objc func didWakeNotification(_ note: Notification) {
+ @MainActor @objc func didWakeNotification(_ note: Notification) {
fireOldTimers()
}
- @objc func importDownloadedTheme(_ note: Notification) {
+ @MainActor @objc func importDownloadedTheme(_ note: Notification) {
guard let userInfo = note.userInfo,
let url = userInfo["url"] as? URL else {
return
@@ -442,7 +442,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
// MARK: Main Window
- func createMainWindowController() -> MainWindowController {
+ @MainActor func createMainWindowController() -> MainWindowController {
let controller: MainWindowController
controller = windowControllerWithName("MainWindow") as! MainWindowController
@@ -453,13 +453,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
return controller
}
- func windowControllerWithName(_ storyboardName: String) -> NSWindowController {
+ @MainActor func windowControllerWithName(_ storyboardName: String) -> NSWindowController {
let storyboard = NSStoryboard(name: NSStoryboard.Name(storyboardName), bundle: nil)
return storyboard.instantiateInitialController()! as! NSWindowController
}
@discardableResult
- func createAndShowMainWindow() -> MainWindowController {
+ @MainActor func createAndShowMainWindow() -> MainWindowController {
let controller = createMainWindowController()
controller.showWindow(self)
@@ -471,7 +471,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
return controller
}
- func createAndShowMainWindowIfNecessary() {
+ @MainActor func createAndShowMainWindowIfNecessary() {
if mainWindowController == nil {
createAndShowMainWindow()
} else {
@@ -479,7 +479,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
}
- func removeMainWindow(_ windowController: MainWindowController) {
+ @MainActor func removeMainWindow(_ windowController: MainWindowController) {
guard mainWindowControllers.count > 1 else { return }
if let index = mainWindowControllers.firstIndex(of: windowController) {
mainWindowControllers.remove(at: index)
@@ -487,7 +487,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
// MARK: NSUserInterfaceValidations
- func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
+ @MainActor func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
if shuttingDown {
return false
}
@@ -533,11 +533,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
// MARK: UNUserNotificationCenterDelegate
- func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
+ @MainActor func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .badge, .sound])
}
- func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
+ @MainActor func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
@@ -553,7 +553,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
// MARK: Add Feed
- func addWebFeed(_ urlString: String?, name: String? = nil, account: Account? = nil, folder: Folder? = nil) {
+ @MainActor func addWebFeed(_ urlString: String?, name: String? = nil, account: Account? = nil, folder: Folder? = nil) {
createAndShowMainWindowIfNecessary()
if mainWindowController!.isDisplayingSheet {
@@ -564,13 +564,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
// MARK: - Dock Badge
- @objc func updateDockBadge() {
+ @MainActor @objc func updateDockBadge() {
let label = unreadCount > 0 ? "\(unreadCount)" : ""
NSApplication.shared.dockTile.badgeLabel = label
}
// MARK: - Actions
- @IBAction func showPreferences(_ sender: Any?) {
+ @MainActor @IBAction func showPreferences(_ sender: Any?) {
if preferencesWindowController == nil {
preferencesWindowController = windowControllerWithName("Preferences")
}
@@ -578,35 +578,35 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
preferencesWindowController!.showWindow(self)
}
- @IBAction func newMainWindow(_ sender: Any?) {
+ @MainActor @IBAction func newMainWindow(_ sender: Any?) {
createAndShowMainWindow()
}
- @IBAction func showMainWindow(_ sender: Any?) {
+ @MainActor @IBAction func showMainWindow(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
mainWindowController?.window?.makeKey()
}
- @IBAction func refreshAll(_ sender: Any?) {
+ @MainActor @IBAction func refreshAll(_ sender: Any?) {
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
}
- @IBAction func showAddWebFeedWindow(_ sender: Any?) {
+ @MainActor @IBAction func showAddWebFeedWindow(_ sender: Any?) {
addWebFeed(nil)
}
- @IBAction func showAddRedditFeedWindow(_ sender: Any?) {
+ @MainActor @IBAction func showAddRedditFeedWindow(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
addFeedController = AddFeedController(hostWindow: mainWindowController!.window!)
addFeedController?.showAddFeedSheet(.redditFeed)
}
- @IBAction func showAddFolderWindow(_ sender: Any?) {
+ @MainActor @IBAction func showAddFolderWindow(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
showAddFolderSheetOnWindow(mainWindowController!.window!)
}
- @IBAction func showKeyboardShortcutsWindow(_ sender: Any?) {
+ @MainActor @IBAction func showKeyboardShortcutsWindow(_ sender: Any?) {
if keyboardShortcutsWindowController == nil {
keyboardShortcutsWindowController = WebViewWindowController(title: NSLocalizedString("Keyboard Shortcuts", comment: "window title"))
@@ -625,7 +625,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
keyboardShortcutsWindowController!.showWindow(self)
}
- @IBAction func toggleInspectorWindow(_ sender: Any?) {
+ @MainActor @IBAction func toggleInspectorWindow(_ sender: Any?) {
if inspectorWindowController == nil {
inspectorWindowController = (windowControllerWithName("Inspector") as! InspectorWindowController)
}
@@ -639,7 +639,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
}
}
- @IBAction func importOPMLFromFile(_ sender: Any?) {
+ @MainActor @IBAction func importOPMLFromFile(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
if mainWindowController!.isDisplayingSheet {
return
@@ -649,7 +649,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
importOPMLController?.runSheetOnWindow(mainWindowController!.window!)
}
- @IBAction func importNNW3FromFile(_ sender: Any?) {
+ @MainActor @IBAction func importNNW3FromFile(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
if mainWindowController!.isDisplayingSheet {
return
@@ -657,7 +657,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
NNW3ImportController.askUserToImportNNW3Subscriptions(window: mainWindowController!.window!)
}
- @IBAction func exportOPML(_ sender: Any?) {
+ @MainActor @IBAction func exportOPML(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
if mainWindowController!.isDisplayingSheet {
return
@@ -667,30 +667,30 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
exportOPMLController?.runSheetOnWindow(mainWindowController!.window!)
}
- @IBAction func addAppNews(_ sender: Any?) {
+ @MainActor @IBAction func addAppNews(_ sender: Any?) {
if AccountManager.shared.anyAccountHasNetNewsWireNewsSubscription() {
return
}
addWebFeed(AccountManager.netNewsWireNewsURL, name: "NetNewsWire News")
}
- @IBAction func openWebsite(_ sender: Any?) {
+ @MainActor @IBAction func openWebsite(_ sender: Any?) {
Browser.open("https://netnewswire.com/", inBackground: false)
}
- @IBAction func showHelp(_ sender: Any?) {
+ @MainActor @IBAction func showHelp(_ sender: Any?) {
Browser.open("https://netnewswire.com/help/mac/6.1/en/", inBackground: false)
}
- @IBAction func gotoToday(_ sender: Any?) {
+ @MainActor @IBAction func gotoToday(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
mainWindowController!.gotoToday(sender)
}
- @IBAction func gotoAllUnread(_ sender: Any?) {
+ @MainActor @IBAction func gotoAllUnread(_ sender: Any?) {
createAndShowMainWindowIfNecessary()
mainWindowController!.gotoAllUnread(sender)
@@ -702,27 +702,27 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
mainWindowController!.gotoStarred(sender)
}
- @IBAction func sortByOldestArticleOnTop(_ sender: Any?) {
+ @MainActor @IBAction func sortByOldestArticleOnTop(_ sender: Any?) {
AppDefaults.shared.timelineSortDirection = .orderedAscending
}
- @IBAction func sortByNewestArticleOnTop(_ sender: Any?) {
+ @MainActor @IBAction func sortByNewestArticleOnTop(_ sender: Any?) {
AppDefaults.shared.timelineSortDirection = .orderedDescending
}
- @IBAction func groupByFeedToggled(_ sender: NSMenuItem) {
+ @MainActor @IBAction func groupByFeedToggled(_ sender: NSMenuItem) {
AppDefaults.shared.timelineGroupByFeed.toggle()
}
- @IBAction func checkForUpdates(_ sender: Any?) {
+ @MainActor @IBAction func checkForUpdates(_ sender: Any?) {
#if !MAC_APP_STORE && !TEST
self.softwareUpdater.checkForUpdates()
#endif
}
- @IBAction func showAbout(_ sender: Any?) {
+ @MainActor @IBAction func showAbout(_ sender: Any?) {
if #available(macOS 12, *) {
for window in NSApplication.shared.windows {
if window.identifier == .aboutNetNewsWire {
@@ -741,7 +741,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
// MARK: - NSMenuDelegate
-extension AppDelegate: NSMenuDelegate {
+@MainActor extension AppDelegate: NSMenuDelegate {
public func menuNeedsUpdate(_ menu: NSMenu) {
let newShareMenu = mainWindowController?.shareMenu
@@ -760,7 +760,7 @@ extension AppDelegate: NSMenuDelegate {
}
// MARK: - Debug Menu
-extension AppDelegate {
+@MainActor extension AppDelegate {
@IBAction func debugSearch(_ sender: Any?) {
AccountManager.shared.defaultAccount.debugRunSearch()
@@ -832,7 +832,7 @@ extension AppDelegate {
}
-internal extension AppDelegate {
+@MainActor internal extension AppDelegate {
func fireOldTimers() {
// It’s possible there’s a refresh timer set to go off in the past.
@@ -1007,7 +1007,7 @@ extension AppDelegate : ScriptingAppDelegate {
}
}
-extension AppDelegate: NSWindowRestoration {
+@MainActor extension AppDelegate: NSWindowRestoration {
@objc static func restoreWindow(withIdentifier identifier: NSUserInterfaceItemIdentifier, state: NSCoder, completionHandler: @escaping (NSWindow?, Error?) -> Void) {
var mainWindow: NSWindow? = nil
@@ -1021,7 +1021,7 @@ extension AppDelegate: NSWindowRestoration {
// Handle Notification Actions
-private extension AppDelegate {
+@MainActor private extension AppDelegate {
func handleMarkAsRead(userInfo: [AnyHashable: Any]) {
markArticle(userInfo: userInfo, statusKey: .read)
diff --git a/Mac/Base.lproj/Preferences.storyboard b/Mac/Base.lproj/Preferences.storyboard
index ec3c0ba73..ddf26b887 100644
--- a/Mac/Base.lproj/Preferences.storyboard
+++ b/Mac/Base.lproj/Preferences.storyboard
@@ -527,16 +527,16 @@
-
+
-
+
-
+
-
+
@@ -643,7 +643,7 @@
-
+
@@ -698,16 +698,16 @@
-
+
-
+
-
+
-
+
@@ -810,7 +810,7 @@
-
+
diff --git a/Mac/Browser.swift b/Mac/Browser.swift
index 7b47dad85..7b0ad4d3f 100644
--- a/Mac/Browser.swift
+++ b/Mac/Browser.swift
@@ -9,7 +9,7 @@
import Foundation
import RSWeb
-struct Browser {
+@MainActor struct Browser {
/// The user-specified default browser for opening web pages.
///
diff --git a/Mac/CrashReporter/CrashReportWindowController.swift b/Mac/CrashReporter/CrashReportWindowController.swift
index 7c7ce9ee7..5579e0ef3 100644
--- a/Mac/CrashReporter/CrashReportWindowController.swift
+++ b/Mac/CrashReporter/CrashReportWindowController.swift
@@ -8,7 +8,7 @@
import AppKit
-final class CrashReportWindowController: NSWindowController {
+@MainActor final class CrashReportWindowController: NSWindowController {
@IBOutlet var textView: NSTextView! {
didSet {
diff --git a/Mac/CrashReporter/CrashReporter.swift b/Mac/CrashReporter/CrashReporter.swift
index b37810a9d..09d1db06b 100644
--- a/Mac/CrashReporter/CrashReporter.swift
+++ b/Mac/CrashReporter/CrashReporter.swift
@@ -16,7 +16,7 @@ import CrashReporter
// At some point this code should probably move into RSCore, so Rainier and any other
// future apps can use it.
-struct CrashReporter {
+@MainActor struct CrashReporter {
struct DefaultsKey {
static let sendCrashLogsAutomaticallyKey = "SendCrashLogsAutomatically"
diff --git a/Mac/ErrorHandler.swift b/Mac/ErrorHandler.swift
index 4ec6f59be..1d332359c 100644
--- a/Mac/ErrorHandler.swift
+++ b/Mac/ErrorHandler.swift
@@ -10,16 +10,13 @@ import AppKit
import Account
import RSCore
-struct ErrorHandler: Logging {
+@MainActor struct ErrorHandler: Logging {
-
-
public static func present(_ error: Error) {
NSApplication.shared.presentError(error)
}
-
+
public static func log(_ error: Error) {
ErrorHandler.logger.error("\(error.localizedDescription, privacy: .public)")
}
-
}
diff --git a/Mac/MainWindow/About/CreditsNetNewsWireView.swift b/Mac/MainWindow/About/CreditsNetNewsWireView.swift
index 88a63fe75..f72318696 100644
--- a/Mac/MainWindow/About/CreditsNetNewsWireView.swift
+++ b/Mac/MainWindow/About/CreditsNetNewsWireView.swift
@@ -66,7 +66,9 @@ struct CreditsNetNewsWireView: View, LoadableAboutData {
.onTapGesture {
guard let url = appCredit.url else { return }
if let _ = URL(string: url) {
- Browser.open(url, inBackground: false)
+ Task { @MainActor in
+ Browser.open(url, inBackground: false)
+ }
}
}
}
diff --git a/Mac/MainWindow/AddFeed/AddFeedController.swift b/Mac/MainWindow/AddFeed/AddFeedController.swift
index 941fca98b..38c27414b 100644
--- a/Mac/MainWindow/AddFeed/AddFeedController.swift
+++ b/Mac/MainWindow/AddFeed/AddFeedController.swift
@@ -22,7 +22,7 @@ import RSParser
// Else,
// display error sheet.
-class AddFeedController: AddFeedWindowControllerDelegate {
+@MainActor final class AddFeedController: AddFeedWindowControllerDelegate {
private let hostWindow: NSWindow
private var addFeedWindowController: AddFeedWindowController?
diff --git a/Mac/MainWindow/AddFeed/AddFeedWIndowController.swift b/Mac/MainWindow/AddFeed/AddFeedWIndowController.swift
index e574d7fa5..50ad03701 100644
--- a/Mac/MainWindow/AddFeed/AddFeedWIndowController.swift
+++ b/Mac/MainWindow/AddFeed/AddFeedWIndowController.swift
@@ -14,7 +14,7 @@ enum AddFeedWindowControllerType {
case redditFeed
}
-protocol AddFeedWindowControllerDelegate: AnyObject {
+@MainActor protocol AddFeedWindowControllerDelegate: AnyObject {
// userEnteredURL will have already been validated and normalized.
func addFeedWindowController(_: AddFeedWindowController, userEnteredURL: URL, userEnteredTitle: String?, container: Container)
@@ -22,7 +22,7 @@ protocol AddFeedWindowControllerDelegate: AnyObject {
}
-protocol AddFeedWindowController {
+@MainActor protocol AddFeedWindowController {
var window: NSWindow? { get }
func runSheetOnWindow(_ hostWindow: NSWindow)
diff --git a/Mac/MainWindow/AddFeed/AddWebFeedWindowController.swift b/Mac/MainWindow/AddFeed/AddWebFeedWindowController.swift
index 16c8a4d72..40b6f6301 100644
--- a/Mac/MainWindow/AddFeed/AddWebFeedWindowController.swift
+++ b/Mac/MainWindow/AddFeed/AddWebFeedWindowController.swift
@@ -12,7 +12,7 @@ import RSTree
import Articles
import Account
-class AddWebFeedWindowController : NSWindowController, AddFeedWindowController {
+@MainActor final class AddWebFeedWindowController : NSWindowController, AddFeedWindowController {
@IBOutlet var urlTextField: NSTextField!
@IBOutlet var nameTextField: NSTextField!
diff --git a/Mac/MainWindow/AddFeed/FolderTreeMenu.swift b/Mac/MainWindow/AddFeed/FolderTreeMenu.swift
index 87250dd6b..1c696f0dc 100644
--- a/Mac/MainWindow/AddFeed/FolderTreeMenu.swift
+++ b/Mac/MainWindow/AddFeed/FolderTreeMenu.swift
@@ -11,7 +11,7 @@ import RSCore
import RSTree
import Account
-class FolderTreeMenu {
+@MainActor final class FolderTreeMenu {
static func createFolderPopupMenu(with rootNode: Node, restrictToSpecialAccounts: Bool = false) -> NSMenu {
diff --git a/Mac/MainWindow/AddFolder/AddFolderWindowController.swift b/Mac/MainWindow/AddFolder/AddFolderWindowController.swift
index 84053ee20..08cc50310 100644
--- a/Mac/MainWindow/AddFolder/AddFolderWindowController.swift
+++ b/Mac/MainWindow/AddFolder/AddFolderWindowController.swift
@@ -10,7 +10,7 @@ import AppKit
import Articles
import Account
-class AddFolderWindowController : NSWindowController {
+@MainActor final class AddFolderWindowController : NSWindowController {
@IBOutlet var folderNameTextField: NSTextField!
@IBOutlet var accountPopupButton: NSPopUpButton!
diff --git a/Mac/MainWindow/AddRedditFeedWindowController.swift b/Mac/MainWindow/AddRedditFeedWindowController.swift
index 55056ad34..0d07abccb 100644
--- a/Mac/MainWindow/AddRedditFeedWindowController.swift
+++ b/Mac/MainWindow/AddRedditFeedWindowController.swift
@@ -12,7 +12,7 @@ import RSTree
import Articles
import Account
-class AddRedditFeedWindowController : NSWindowController, AddFeedWindowController {
+@MainActor final class AddRedditFeedWindowController : NSWindowController, AddFeedWindowController {
@IBOutlet weak var typePopupButton: NSPopUpButton!
@IBOutlet weak var typeDescriptionLabel: NSTextField!
diff --git a/Mac/MainWindow/ArticleExtractorButton.swift b/Mac/MainWindow/ArticleExtractorButton.swift
index d5d30ccf8..1ea097769 100644
--- a/Mac/MainWindow/ArticleExtractorButton.swift
+++ b/Mac/MainWindow/ArticleExtractorButton.swift
@@ -15,7 +15,7 @@ enum ArticleExtractorButtonState {
case off
}
-class ArticleExtractorButton: NSButton {
+@MainActor final class ArticleExtractorButton: NSButton {
public var rightClickAction: Selector?
diff --git a/Mac/MainWindow/Detail/DetailIconSchemeHandler.swift b/Mac/MainWindow/Detail/DetailIconSchemeHandler.swift
index 4aee30c11..334605cbe 100644
--- a/Mac/MainWindow/Detail/DetailIconSchemeHandler.swift
+++ b/Mac/MainWindow/Detail/DetailIconSchemeHandler.swift
@@ -10,7 +10,7 @@ import Foundation
import WebKit
import Articles
-class DetailIconSchemeHandler: NSObject, WKURLSchemeHandler {
+final class DetailIconSchemeHandler: NSObject, WKURLSchemeHandler {
var currentArticle: Article?
diff --git a/Mac/MainWindow/Detail/DetailStatusBarView.swift b/Mac/MainWindow/Detail/DetailStatusBarView.swift
index eea5f72d2..119f5b112 100644
--- a/Mac/MainWindow/Detail/DetailStatusBarView.swift
+++ b/Mac/MainWindow/Detail/DetailStatusBarView.swift
@@ -9,7 +9,7 @@
import AppKit
import Articles
-final class DetailStatusBarView: NSView {
+@MainActor final class DetailStatusBarView: NSView {
@IBOutlet var urlLabel: NSTextField!
diff --git a/Mac/MainWindow/Detail/DetailViewController.swift b/Mac/MainWindow/Detail/DetailViewController.swift
index bcfd2533a..e4b099bf4 100644
--- a/Mac/MainWindow/Detail/DetailViewController.swift
+++ b/Mac/MainWindow/Detail/DetailViewController.swift
@@ -20,7 +20,7 @@ enum DetailState: Equatable {
case extracted(Article, ExtractedArticle, CGFloat?)
}
-final class DetailViewController: NSViewController, WKUIDelegate {
+@MainActor final class DetailViewController: NSViewController, WKUIDelegate {
@IBOutlet var containerView: DetailContainerView!
@IBOutlet var statusBarView: DetailStatusBarView!
diff --git a/Mac/MainWindow/Detail/DetailWebView.swift b/Mac/MainWindow/Detail/DetailWebView.swift
index 56f5d7812..5bdf0cbfc 100644
--- a/Mac/MainWindow/Detail/DetailWebView.swift
+++ b/Mac/MainWindow/Detail/DetailWebView.swift
@@ -10,7 +10,7 @@ import AppKit
import WebKit
import RSCore
-final class DetailWebView: WKWebView {
+@MainActor final class DetailWebView: WKWebView {
weak var keyboardDelegate: KeyboardDelegate?
diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift
index 6d669cf5f..36c691c42 100644
--- a/Mac/MainWindow/Detail/DetailWebViewController.swift
+++ b/Mac/MainWindow/Detail/DetailWebViewController.swift
@@ -17,7 +17,7 @@ protocol DetailWebViewControllerDelegate: AnyObject {
func mouseDidExit(_: DetailWebViewController)
}
-final class DetailWebViewController: NSViewController {
+@MainActor final class DetailWebViewController: NSViewController {
weak var delegate: DetailWebViewControllerDelegate?
var webView: DetailWebView!
diff --git a/Mac/MainWindow/MainWindow.swift b/Mac/MainWindow/MainWindow.swift
index 4fe147deb..18409f76a 100644
--- a/Mac/MainWindow/MainWindow.swift
+++ b/Mac/MainWindow/MainWindow.swift
@@ -8,7 +8,7 @@
import Foundation
-class MainWindow: NSWindow {
+@MainActor class MainWindow: NSWindow {
override func sendEvent(_ event: NSEvent) {
diff --git a/Mac/MainWindow/MainWindowController.swift b/Mac/MainWindow/MainWindowController.swift
index 9e7e485e4..514ad4040 100644
--- a/Mac/MainWindow/MainWindowController.swift
+++ b/Mac/MainWindow/MainWindowController.swift
@@ -16,7 +16,7 @@ enum TimelineSourceMode {
case regular, search
}
-class MainWindowController : NSWindowController, NSUserInterfaceValidations {
+@MainActor final class MainWindowController : NSWindowController, NSUserInterfaceValidations {
@IBOutlet weak var articleThemePopUpButton: NSPopUpButton?
diff --git a/Mac/MainWindow/NNW3/NNW3ImportController.swift b/Mac/MainWindow/NNW3/NNW3ImportController.swift
index 32084490e..b36c1e7ee 100644
--- a/Mac/MainWindow/NNW3/NNW3ImportController.swift
+++ b/Mac/MainWindow/NNW3/NNW3ImportController.swift
@@ -9,7 +9,7 @@
import AppKit
import Account
-struct NNW3ImportController {
+@MainActor struct NNW3ImportController {
/// Import NNW3 subscriptions if they exist.
/// Return true if Subscriptions.plist was found and subscriptions were imported.
diff --git a/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryViewController.swift b/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryViewController.swift
index 110377b11..a8c2484c2 100644
--- a/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryViewController.swift
+++ b/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryViewController.swift
@@ -9,7 +9,7 @@
import AppKit
import Account
-final class NNW3OpenPanelAccessoryViewController: NSViewController {
+@MainActor final class NNW3OpenPanelAccessoryViewController: NSViewController {
@IBOutlet weak var accountPopUpButton: NSPopUpButton!
diff --git a/Mac/MainWindow/OPML/ExportOPMLWindowController.swift b/Mac/MainWindow/OPML/ExportOPMLWindowController.swift
index 4b2ce20a6..0ff8284e0 100644
--- a/Mac/MainWindow/OPML/ExportOPMLWindowController.swift
+++ b/Mac/MainWindow/OPML/ExportOPMLWindowController.swift
@@ -9,7 +9,7 @@
import AppKit
import Account
-class ExportOPMLWindowController: NSWindowController {
+@MainActor final class ExportOPMLWindowController: NSWindowController {
@IBOutlet weak var accountPopUpButton: NSPopUpButton!
private weak var hostWindow: NSWindow?
diff --git a/Mac/MainWindow/OPML/ImportOPMLWindowController.swift b/Mac/MainWindow/OPML/ImportOPMLWindowController.swift
index f0737fe93..3a53c3de3 100644
--- a/Mac/MainWindow/OPML/ImportOPMLWindowController.swift
+++ b/Mac/MainWindow/OPML/ImportOPMLWindowController.swift
@@ -9,7 +9,7 @@
import AppKit
import Account
-class ImportOPMLWindowController: NSWindowController {
+@MainActor final class ImportOPMLWindowController: NSWindowController {
@IBOutlet weak var accountPopUpButton: NSPopUpButton!
private weak var hostWindow: NSWindow?
diff --git a/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift b/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift
index 0ec462a19..ffc1162be 100644
--- a/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift
+++ b/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift
@@ -11,7 +11,7 @@ import RSCore
import Account
import RSTree
-class SidebarCell : NSTableCellView {
+@MainActor final class SidebarCell : NSTableCellView {
var iconImage: IconImage? {
didSet {
diff --git a/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift b/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift
index c13996732..e5824ba6a 100644
--- a/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift
+++ b/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift
@@ -8,7 +8,7 @@
import AppKit
-struct SidebarCellAppearance: Equatable {
+@MainActor struct SidebarCellAppearance: Equatable {
let imageSize: CGSize
let imageMarginRight: CGFloat = 4.0
diff --git a/Mac/MainWindow/Sidebar/Cell/SidebarCellLayout.swift b/Mac/MainWindow/Sidebar/Cell/SidebarCellLayout.swift
index e054b924a..ed9e91a94 100644
--- a/Mac/MainWindow/Sidebar/Cell/SidebarCellLayout.swift
+++ b/Mac/MainWindow/Sidebar/Cell/SidebarCellLayout.swift
@@ -11,7 +11,7 @@ import RSCore
// image - title - unreadCount
-struct SidebarCellLayout {
+@MainActor struct SidebarCellLayout {
let faviconRect: CGRect
let titleRect: CGRect
diff --git a/Mac/MainWindow/Sidebar/Renaming/RenameWindowController.swift b/Mac/MainWindow/Sidebar/Renaming/RenameWindowController.swift
index 5cb8b6309..41d1dd07b 100644
--- a/Mac/MainWindow/Sidebar/Renaming/RenameWindowController.swift
+++ b/Mac/MainWindow/Sidebar/Renaming/RenameWindowController.swift
@@ -13,7 +13,7 @@ protocol RenameWindowControllerDelegate {
func renameWindowController(_ windowController: RenameWindowController, didRenameObject: Any, withNewName: String)
}
-final class RenameWindowController: NSWindowController {
+@MainActor final class RenameWindowController: NSWindowController {
@IBOutlet var renamePrompt: NSTextField!
@IBOutlet var newTitleTextField: NSTextField!
diff --git a/Mac/MainWindow/Sidebar/SidebarDeleteItemsAlert.swift b/Mac/MainWindow/Sidebar/SidebarDeleteItemsAlert.swift
index 899c29cf1..571137231 100644
--- a/Mac/MainWindow/Sidebar/SidebarDeleteItemsAlert.swift
+++ b/Mac/MainWindow/Sidebar/SidebarDeleteItemsAlert.swift
@@ -10,7 +10,7 @@ import AppKit
import RSTree
import Account
-enum SidebarDeleteItemsAlert {
+@MainActor enum SidebarDeleteItemsAlert {
/// Builds a delete confirmation dialog for the supplied nodes
static func build(_ nodes: [Node]) -> NSAlert {
diff --git a/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift b/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift
index 7e0478d5f..a4fb7b5e9 100644
--- a/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift
+++ b/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift
@@ -492,7 +492,7 @@ private extension SidebarOutlineDataSource {
return true
}
- func acceptSingleNonLocalFeedDrop(_ outlineView: NSOutlineView, _ draggedFeed: PasteboardWebFeed, _ parentNode: Node, _ index: Int) -> Bool {
+ @MainActor func acceptSingleNonLocalFeedDrop(_ outlineView: NSOutlineView, _ draggedFeed: PasteboardWebFeed, _ parentNode: Node, _ index: Int) -> Bool {
guard nodeIsDropTarget(parentNode), index == NSOutlineViewDropOnItemIndex else {
return false
}
diff --git a/Mac/MainWindow/Sidebar/SidebarOutlineView.swift b/Mac/MainWindow/Sidebar/SidebarOutlineView.swift
index 2be34e87c..eefc29a63 100644
--- a/Mac/MainWindow/Sidebar/SidebarOutlineView.swift
+++ b/Mac/MainWindow/Sidebar/SidebarOutlineView.swift
@@ -10,7 +10,7 @@ import AppKit
import RSCore
import RSTree
-class SidebarOutlineView : NSOutlineView {
+@MainActor class SidebarOutlineView : NSOutlineView {
@IBOutlet var keyboardDelegate: KeyboardDelegate!
diff --git a/Mac/MainWindow/Sidebar/SidebarStatusBarView.swift b/Mac/MainWindow/Sidebar/SidebarStatusBarView.swift
index 315ea4ae3..6a85a6f9f 100644
--- a/Mac/MainWindow/Sidebar/SidebarStatusBarView.swift
+++ b/Mac/MainWindow/Sidebar/SidebarStatusBarView.swift
@@ -12,7 +12,7 @@ import Articles
import RSWeb
import Account
-final class SidebarStatusBarView: NSView {
+@MainActor final class SidebarStatusBarView: NSView {
@IBOutlet var progressIndicator: NSProgressIndicator!
@IBOutlet var progressLabel: NSTextField!
diff --git a/Mac/MainWindow/Timeline/TimelineContainerView.swift b/Mac/MainWindow/Timeline/TimelineContainerView.swift
index e75475405..6a8b42298 100644
--- a/Mac/MainWindow/Timeline/TimelineContainerView.swift
+++ b/Mac/MainWindow/Timeline/TimelineContainerView.swift
@@ -8,7 +8,7 @@
import AppKit
-final class TimelineContainerView: NSView {
+@MainActor final class TimelineContainerView: NSView {
private var contentViewConstraints: [NSLayoutConstraint]?
diff --git a/Mac/MainWindow/Timeline/TimelineContainerViewController.swift b/Mac/MainWindow/Timeline/TimelineContainerViewController.swift
index c697a1a0c..81ec39b30 100644
--- a/Mac/MainWindow/Timeline/TimelineContainerViewController.swift
+++ b/Mac/MainWindow/Timeline/TimelineContainerViewController.swift
@@ -17,7 +17,7 @@ protocol TimelineContainerViewControllerDelegate: AnyObject {
}
-final class TimelineContainerViewController: NSViewController {
+@MainActor final class TimelineContainerViewController: NSViewController {
@IBOutlet weak var viewOptionsPopUpButton: NSPopUpButton!
@IBOutlet weak var newestToOldestMenuItem: NSMenuItem!
diff --git a/Mac/MainWindow/Timeline/TimelineTableRowView.swift b/Mac/MainWindow/Timeline/TimelineTableRowView.swift
index 54d87479c..d4598ef1e 100644
--- a/Mac/MainWindow/Timeline/TimelineTableRowView.swift
+++ b/Mac/MainWindow/Timeline/TimelineTableRowView.swift
@@ -8,7 +8,7 @@
import AppKit
-class TimelineTableRowView : NSTableRowView {
+@MainActor final class TimelineTableRowView : NSTableRowView {
private var separator: NSView?
diff --git a/Mac/MainWindow/Timeline/TimelineTableView.swift b/Mac/MainWindow/Timeline/TimelineTableView.swift
index e70bbed17..f5d8a9469 100644
--- a/Mac/MainWindow/Timeline/TimelineTableView.swift
+++ b/Mac/MainWindow/Timeline/TimelineTableView.swift
@@ -9,7 +9,7 @@
import AppKit
import RSCore
-class TimelineTableView: NSTableView {
+@MainActor final class TimelineTableView: NSTableView {
weak var keyboardDelegate: KeyboardDelegate?
diff --git a/Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift b/Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift
index 81c3e3ce4..0d3a9488e 100644
--- a/Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift
+++ b/Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift
@@ -8,7 +8,7 @@
import RSCore
-extension URLPasteboardWriter {
+@MainActor extension URLPasteboardWriter {
/// Copy URL strings, alerting the user the first time the array of URL strings contains `nil`.
/// - Parameters:
diff --git a/Mac/Preferences/Accounts/AccountCell.swift b/Mac/Preferences/Accounts/AccountCell.swift
index 7a1dbecef..b6fb2eef3 100644
--- a/Mac/Preferences/Accounts/AccountCell.swift
+++ b/Mac/Preferences/Accounts/AccountCell.swift
@@ -8,7 +8,7 @@
import AppKit
-class AccountCell: NSTableCellView {
+@MainActor class AccountCell: NSTableCellView {
private var originalImage: NSImage?
diff --git a/Mac/Preferences/Accounts/AccountsAddCloudKitWindowController.swift b/Mac/Preferences/Accounts/AccountsAddCloudKitWindowController.swift
index 6c01d9ef9..945453122 100644
--- a/Mac/Preferences/Accounts/AccountsAddCloudKitWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsAddCloudKitWindowController.swift
@@ -17,7 +17,7 @@ enum AccountsAddCloudKitWindowControllerError: LocalizedError {
}
}
-class AccountsAddCloudKitWindowController: NSWindowController {
+@MainActor class AccountsAddCloudKitWindowController: NSWindowController {
@IBOutlet weak var limitationsAndSolutionsTextField: NSTextField!
diff --git a/Mac/Preferences/Accounts/AccountsAddLocalWindowController.swift b/Mac/Preferences/Accounts/AccountsAddLocalWindowController.swift
index 8aedbccd7..373ffea30 100644
--- a/Mac/Preferences/Accounts/AccountsAddLocalWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsAddLocalWindowController.swift
@@ -9,7 +9,7 @@
import AppKit
import Account
-class AccountsAddLocalWindowController: NSWindowController {
+@MainActor class AccountsAddLocalWindowController: NSWindowController {
@IBOutlet private weak var nameTextField: NSTextField!
@IBOutlet private weak var localAccountNameTextField: NSTextField!
diff --git a/Mac/Preferences/Accounts/AccountsDetailViewController.swift b/Mac/Preferences/Accounts/AccountsDetailViewController.swift
index 3fe5487ee..6b395249e 100644
--- a/Mac/Preferences/Accounts/AccountsDetailViewController.swift
+++ b/Mac/Preferences/Accounts/AccountsDetailViewController.swift
@@ -9,7 +9,7 @@
import AppKit
import Account
-final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate {
+@MainActor final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate {
@IBOutlet weak var typeLabel: NSTextField!
@IBOutlet weak var nameTextField: NSTextField!
diff --git a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift
index 6ac802851..687e0c864 100644
--- a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift
@@ -12,7 +12,7 @@ import RSCore
import RSWeb
import Secrets
-class AccountsFeedbinWindowController: NSWindowController, Logging {
+@MainActor class AccountsFeedbinWindowController: NSWindowController, Logging {
@IBOutlet weak var signInTextField: NSTextField!
@IBOutlet weak var noAccountTextField: NSTextField!
diff --git a/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift
index 0af42818e..9cb726e17 100644
--- a/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift
@@ -12,7 +12,7 @@ import RSWeb
import RSCore
import Secrets
-class AccountsNewsBlurWindowController: NSWindowController, Logging {
+@MainActor class AccountsNewsBlurWindowController: NSWindowController, Logging {
@IBOutlet weak var signInTextField: NSTextField!
@IBOutlet weak var noAccountTextField: NSTextField!
diff --git a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift
index 307f5b8b5..66a0173cb 100644
--- a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift
+++ b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift
@@ -17,7 +17,7 @@ protocol AccountsPreferencesAddAccountDelegate {
}
// MARK: - AccountsPreferencesViewController
-final class AccountsPreferencesViewController: NSViewController {
+@MainActor final class AccountsPreferencesViewController: NSViewController {
@IBOutlet weak var tableView: NSTableView!
@IBOutlet weak var detailView: NSView!
diff --git a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift
index b127003db..e282f327e 100644
--- a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift
@@ -12,7 +12,7 @@ import RSWeb
import RSCore
import Secrets
-class AccountsReaderAPIWindowController: NSWindowController, Logging {
+@MainActor class AccountsReaderAPIWindowController: NSWindowController, Logging {
@IBOutlet weak var titleImageView: NSImageView!
@IBOutlet weak var titleLabel: NSTextField!
diff --git a/Mac/Preferences/Advanced/AdvancedPreferencesViewController.swift b/Mac/Preferences/Advanced/AdvancedPreferencesViewController.swift
index a48e9fe91..53ccc3aee 100644
--- a/Mac/Preferences/Advanced/AdvancedPreferencesViewController.swift
+++ b/Mac/Preferences/Advanced/AdvancedPreferencesViewController.swift
@@ -8,11 +8,10 @@
import AppKit
-final class AdvancedPreferencesViewController: NSViewController {
+@MainActor final class AdvancedPreferencesViewController: NSViewController {
@IBOutlet var releaseBuildsButton: NSButton!
@IBOutlet var testBuildsButton: NSButton!
- @IBOutlet weak var privacyPolicyTextField: NSTextField!
let releaseBuildsURL = Bundle.main.infoDictionary!["SUFeedURL"]! as! String
let testBuildsURL = Bundle.main.infoDictionary!["FeedURLForTestBuilds"]! as! String
@@ -35,7 +34,6 @@ final class AdvancedPreferencesViewController: NSViewController {
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
didRegisterForNotification = true
}
- privacyPolicyTextField.attributedStringValue = AppAssets.privacyPolicyLink
}
@IBAction func updateTypeButtonClicked(_ sender: Any?) {
diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift
index f94d0ae59..0a97d68ae 100644
--- a/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift
+++ b/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift
@@ -8,7 +8,7 @@
import Cocoa
-class ExtensionPointDetailViewController: NSViewController {
+@MainActor class ExtensionPointDetailViewController: NSViewController {
@IBOutlet weak var imageView: NSImageView!
@IBOutlet weak var titleLabel: NSTextField!
diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift
index f8aed7ff5..1af42d40e 100644
--- a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift
+++ b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift
@@ -11,7 +11,7 @@ import AuthenticationServices
import OAuthSwift
import Secrets
-class ExtensionPointEnableWindowController: NSWindowController {
+@MainActor class ExtensionPointEnableWindowController: NSWindowController {
@IBOutlet weak var imageView: NSImageView!
@IBOutlet weak var titleLabel: NSTextField!
diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift
index d79525d30..16a797a80 100644
--- a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift
+++ b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift
@@ -16,7 +16,7 @@ protocol ExtensionPointPreferencesEnabler: AnyObject {
func enable(_ extensionPointType: ExtensionPoint.Type)
}
-final class ExtensionPointPreferencesViewController: NSViewController {
+@MainActor final class ExtensionPointPreferencesViewController: NSViewController {
@IBOutlet weak var tableView: NSTableView!
@IBOutlet weak var detailView: NSView!
diff --git a/Mac/Preferences/General/GeneralPrefencesViewController.swift b/Mac/Preferences/General/GeneralPrefencesViewController.swift
index 19fa9b7a0..0b55a756d 100644
--- a/Mac/Preferences/General/GeneralPrefencesViewController.swift
+++ b/Mac/Preferences/General/GeneralPrefencesViewController.swift
@@ -11,7 +11,7 @@ import RSCore
import RSWeb
import UserNotifications
-final class GeneralPreferencesViewController: NSViewController {
+@MainActor final class GeneralPreferencesViewController: NSViewController {
private var userNotificationSettings: UNNotificationSettings?
diff --git a/Mac/Preferences/PreferencesControlsBackgroundView.swift b/Mac/Preferences/PreferencesControlsBackgroundView.swift
index 36353dd6b..307109c50 100644
--- a/Mac/Preferences/PreferencesControlsBackgroundView.swift
+++ b/Mac/Preferences/PreferencesControlsBackgroundView.swift
@@ -9,7 +9,7 @@
import AppKit
import RSCore
-final class PreferencesControlsBackgroundView: NSView {
+@MainActor final class PreferencesControlsBackgroundView: NSView {
private let lightModeFillColor = NSColor(white: 0.97, alpha: 1.0)
private let darkModeFillColor = NSColor(red: 0.32, green: 0.34, blue: 0.35, alpha: 1.0)
diff --git a/Mac/Preferences/PreferencesTableViewBackgroundView.swift b/Mac/Preferences/PreferencesTableViewBackgroundView.swift
index 34548e429..df9fce2db 100644
--- a/Mac/Preferences/PreferencesTableViewBackgroundView.swift
+++ b/Mac/Preferences/PreferencesTableViewBackgroundView.swift
@@ -8,7 +8,7 @@
import AppKit
-final class PreferencesTableViewBackgroundView: NSView {
+@MainActor final class PreferencesTableViewBackgroundView: NSView {
let lightBorderColor = NSColor(white: 0.71, alpha: 1.0)
let darkBorderColor = NSColor(red: 0.41, green: 0.43, blue: 0.44, alpha: 1.0)
diff --git a/Mac/Preferences/PreferencesWindowController.swift b/Mac/Preferences/PreferencesWindowController.swift
index 738aa5d81..f4d7b898f 100644
--- a/Mac/Preferences/PreferencesWindowController.swift
+++ b/Mac/Preferences/PreferencesWindowController.swift
@@ -28,7 +28,7 @@ private struct ToolbarItemIdentifier {
static let Advanced = "Advanced"
}
-class PreferencesWindowController : NSWindowController, NSToolbarDelegate {
+@MainActor class PreferencesWindowController : NSWindowController, NSToolbarDelegate {
private let windowWidth = CGFloat(512.0) // Width is constant for all views; only the height changes
private var viewControllers = [String: NSViewController]()
diff --git a/Mac/Resources/Info.plist b/Mac/Resources/Info.plist
index 90970f567..a5e21c04c 100644
--- a/Mac/Resources/Info.plist
+++ b/Mac/Resources/Info.plist
@@ -62,7 +62,7 @@
NSAppleScriptEnabled
NSHumanReadableCopyright
- Copyright © 2002-2022 Brent Simmons. All rights reserved.
+ Copyright © 2002-2023 Brent Simmons. All rights reserved.
NSMainStoryboardFile
Main
NSPrincipalClass
diff --git a/Mac/Scriptability/AppDelegate+Scriptability.swift b/Mac/Scriptability/AppDelegate+Scriptability.swift
index 07f3057c2..a16334eaf 100644
--- a/Mac/Scriptability/AppDelegate+Scriptability.swift
+++ b/Mac/Scriptability/AppDelegate+Scriptability.swift
@@ -39,7 +39,7 @@ extension AppDelegate : AppDelegateAppleEvents {
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(AppDelegate.getURL(_:_:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
}
- @objc func getURL(_ event: NSAppleEventDescriptor, _ withReplyEvent: NSAppleEventDescriptor) {
+ @MainActor @objc func getURL(_ event: NSAppleEventDescriptor, _ withReplyEvent: NSAppleEventDescriptor) {
guard var urlString = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue else {
return
@@ -63,7 +63,9 @@ extension AppDelegate : AppDelegateAppleEvents {
do {
try ArticleThemeDownloader.shared.handleFile(at: location)
} catch {
- self.presentThemeImportError(error)
+ Task { @MainActor in
+ self.presentThemeImportError(error)
+ }
}
}
task.resume()
diff --git a/Shared/Article Extractor/ArticleExtractor.swift b/Shared/Article Extractor/ArticleExtractor.swift
index 1fd4d151b..1b6cdd4f3 100644
--- a/Shared/Article Extractor/ArticleExtractor.swift
+++ b/Shared/Article Extractor/ArticleExtractor.swift
@@ -40,10 +40,10 @@ class ArticleExtractor: Logging {
let clientURL = "https://extract.feedbin.com/parser"
let username = SecretsManager.provider.mercuryClientId
- let signiture = articleLink.hmacUsingSHA1(key: SecretsManager.provider.mercuryClientSecret)
+ let signature = articleLink.hmacUsingSHA1(key: SecretsManager.provider.mercuryClientSecret)
if let base64URL = articleLink.data(using: .utf8)?.base64EncodedString() {
- let fullURL = "\(clientURL)/\(username)/\(signiture)?base64_url=\(base64URL)"
+ let fullURL = "\(clientURL)/\(username)/\(signature)?base64_url=\(base64URL)"
if let url = URL(string: fullURL) {
self.url = url
return
diff --git a/Shared/ArticleStyles/ArticleThemesManager.swift b/Shared/ArticleStyles/ArticleThemesManager.swift
index d11540c9d..819d67ce1 100644
--- a/Shared/ArticleStyles/ArticleThemesManager.swift
+++ b/Shared/ArticleStyles/ArticleThemesManager.swift
@@ -88,7 +88,9 @@ final class ArticleThemesManager: NSObject, NSFilePresenter, Logging, Observable
do {
currentTheme = try articleThemeWithThemeName(currentThemeName)
} catch {
- appDelegate.presentThemeImportError(error)
+ Task { @MainActor in
+ appDelegate.presentThemeImportError(error)
+ }
}
}
}
diff --git a/Shared/Exporters/OPMLExporter.swift b/Shared/Exporters/OPMLExporter.swift
index cba135a17..46d232e11 100644
--- a/Shared/Exporters/OPMLExporter.swift
+++ b/Shared/Exporters/OPMLExporter.swift
@@ -10,7 +10,7 @@ import Foundation
import Account
import RSCore
-struct OPMLExporter {
+@MainActor struct OPMLExporter {
static func OPMLString(with account: Account, title: String) -> String {
diff --git a/Shared/Extensions/CacheCleaner.swift b/Shared/Extensions/CacheCleaner.swift
index b80896c5d..14046d523 100644
--- a/Shared/Extensions/CacheCleaner.swift
+++ b/Shared/Extensions/CacheCleaner.swift
@@ -10,7 +10,7 @@ import Foundation
import RSWeb
import RSCore
-struct CacheCleaner: Logging {
+@MainActor struct CacheCleaner: Logging {
static func purgeIfNecessary() {
diff --git a/Shared/Importers/DefaultFeeds.opml b/Shared/Importers/DefaultFeeds.opml
index 04132dbaa..ecac3d91e 100644
--- a/Shared/Importers/DefaultFeeds.opml
+++ b/Shared/Importers/DefaultFeeds.opml
@@ -5,12 +5,17 @@
+
+
+
+
+
diff --git a/Shared/Importers/DefaultFeedsImporter.swift b/Shared/Importers/DefaultFeedsImporter.swift
index 8ed67d3b9..d02b2cec3 100644
--- a/Shared/Importers/DefaultFeedsImporter.swift
+++ b/Shared/Importers/DefaultFeedsImporter.swift
@@ -10,7 +10,7 @@ import Foundation
import Account
import RSCore
-struct DefaultFeedsImporter {
+@MainActor struct DefaultFeedsImporter {
static func importDefaultFeeds(account: Account) {
let defaultFeedsURL = Bundle.main.url(forResource: "DefaultFeeds", withExtension: "opml")!
diff --git a/iOS/MasterFeed/MasterFeedViewController.swift b/iOS/MasterFeed/MasterFeedViewController.swift
index 422c3f71f..82a7637a6 100644
--- a/iOS/MasterFeed/MasterFeedViewController.swift
+++ b/iOS/MasterFeed/MasterFeedViewController.swift
@@ -694,7 +694,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
private func showTwitterDeprecationAlert() {
let alert = UIAlertController(title: NSLocalizedString("Twitter Integration Removed", comment: "Twitter Integration Removed"),
- message: NSLocalizedString("On February 1, 2023, Twitter announced the end of free access to the Twitter API, effective February 9.\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 message"),
+ message: 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 message"),
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel))
diff --git a/iOS/MasterTimeline/MasterTimelineViewController.swift b/iOS/MasterTimeline/MasterTimelineViewController.swift
index 1fbf7fd85..804aeaf4f 100644
--- a/iOS/MasterTimeline/MasterTimelineViewController.swift
+++ b/iOS/MasterTimeline/MasterTimelineViewController.swift
@@ -34,7 +34,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
private var markAsReadOnScrollWorkItem: DispatchWorkItem?
private var markAsReadOnScrollStart: Int?
private var markAsReadOnScrollEnd: Int?
- private var lastVerticlePosition: CGFloat = 0
+ private var lastVerticalPosition: CGFloat = 0
var mainControllerIdentifier = MainControllerIdentifier.masterTimeline
@@ -696,7 +696,7 @@ private extension MasterTimelineViewController {
}
func applyChanges(animated: Bool, completion: (() -> Void)? = nil) {
- lastVerticlePosition = 0
+ lastVerticalPosition = 0
if coordinator.articles.count == 0 {
tableView.rowHeight = tableView.estimatedRowHeight
@@ -753,15 +753,15 @@ private extension MasterTimelineViewController {
func markAsReadOnScroll() {
// Only try to mark if we are scrolling up
defer {
- lastVerticlePosition = tableView.contentOffset.y
+ lastVerticalPosition = tableView.contentOffset.y
}
- guard lastVerticlePosition < tableView.contentOffset.y else {
+ guard lastVerticalPosition < tableView.contentOffset.y else {
return
}
// Implement Mark As Read on Scroll where we mark after the leading edge goes a little beyond the safe area inset
guard AppDefaults.shared.markArticlesAsReadOnScroll,
- lastVerticlePosition < tableView.contentOffset.y,
+ lastVerticalPosition < tableView.contentOffset.y,
let firstVisibleIndexPath = tableView.indexPathsForVisibleRows?.first else { return }
let firstVisibleRowRect = tableView.rectForRow(at: firstVisibleIndexPath)
diff --git a/iOS/TitleActivityItemSource.swift b/iOS/TitleActivityItemSource.swift
index fff0609aa..ef5d9c3cc 100644
--- a/iOS/TitleActivityItemSource.swift
+++ b/iOS/TitleActivityItemSource.swift
@@ -29,8 +29,6 @@ class TitleActivityItemSource: NSObject, UIActivityItemSource {
switch activityType.rawValue {
case "com.omnigroup.OmniFocus3.iOS.QuickEntry",
"com.culturedcode.ThingsiPhone.ShareExtension",
- "com.tapbots.Tweetbot4.shareextension",
- "com.tapbots.Tweetbot6.shareextension",
"com.buffer.buffer.Buffer":
return title
default:
diff --git a/xcconfig/common/NetNewsWire_ios_target_common.xcconfig b/xcconfig/common/NetNewsWire_ios_target_common.xcconfig
index 6cc3d75cc..c290664ef 100644
--- a/xcconfig/common/NetNewsWire_ios_target_common.xcconfig
+++ b/xcconfig/common/NetNewsWire_ios_target_common.xcconfig
@@ -1,7 +1,7 @@
// High Level Settings common to both the iOS application and any extensions we bundle with it
MARKETING_VERSION = 6.1.1
-CURRENT_PROJECT_VERSION = 6114
+CURRENT_PROJECT_VERSION = 6115
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon