diff --git a/Ice/Utilities/EventMonitors/GlobalEventMonitor.swift b/Ice/Events/EventMonitors/GlobalEventMonitor.swift similarity index 100% rename from Ice/Utilities/EventMonitors/GlobalEventMonitor.swift rename to Ice/Events/EventMonitors/GlobalEventMonitor.swift diff --git a/Ice/Utilities/EventMonitors/LocalEventMonitor.swift b/Ice/Events/EventMonitors/LocalEventMonitor.swift similarity index 100% rename from Ice/Utilities/EventMonitors/LocalEventMonitor.swift rename to Ice/Events/EventMonitors/LocalEventMonitor.swift diff --git a/Ice/Utilities/EventMonitors/RunLoopLocalEventMonitor.swift b/Ice/Events/EventMonitors/RunLoopLocalEventMonitor.swift similarity index 100% rename from Ice/Utilities/EventMonitors/RunLoopLocalEventMonitor.swift rename to Ice/Events/EventMonitors/RunLoopLocalEventMonitor.swift diff --git a/Ice/Utilities/EventMonitors/UniversalEventMonitor.swift b/Ice/Events/EventMonitors/UniversalEventMonitor.swift similarity index 100% rename from Ice/Utilities/EventMonitors/UniversalEventMonitor.swift rename to Ice/Events/EventMonitors/UniversalEventMonitor.swift diff --git a/Ice/Utilities/EventMonitors/EventTap.swift b/Ice/Events/EventTap.swift similarity index 100% rename from Ice/Utilities/EventMonitors/EventTap.swift rename to Ice/Events/EventTap.swift diff --git a/Ice/Main/AppDelegate.swift b/Ice/Main/AppDelegate.swift index 89f5bde3..4e93dec0 100644 --- a/Ice/Main/AppDelegate.swift +++ b/Ice/Main/AppDelegate.swift @@ -22,9 +22,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate { // Allow the app to set the cursor in the background. appState.setsCursorInBackground = true - - // Set up the shared screen state manager. - ScreenStateManager.setUpSharedManager() } func applicationDidFinishLaunching(_ notification: Notification) { diff --git a/Ice/Main/IceApp.swift b/Ice/Main/IceApp.swift index ae9cf691..c0a4457f 100644 --- a/Ice/Main/IceApp.swift +++ b/Ice/Main/IceApp.swift @@ -12,7 +12,7 @@ struct IceApp: App { init() { NSSplitViewItem.swizzle() - MigrationManager(appState: appState).migrateAll() + MigrationManager.migrateAll(appState: appState) appDelegate.assignAppState(appState) } diff --git a/Ice/Utilities/Swizzling/NSSplitViewItem+swizzledCanCollapse.swift b/Ice/Swizzling/NSSplitViewItem+swizzledCanCollapse.swift similarity index 100% rename from Ice/Utilities/Swizzling/NSSplitViewItem+swizzledCanCollapse.swift rename to Ice/Swizzling/NSSplitViewItem+swizzledCanCollapse.swift diff --git a/Ice/Utilities/MigrationManager.swift b/Ice/Utilities/MigrationManager.swift index 01bfc87a..dfcb5eb8 100644 --- a/Ice/Utilities/MigrationManager.swift +++ b/Ice/Utilities/MigrationManager.swift @@ -14,18 +14,20 @@ struct MigrationManager { extension MigrationManager { /// Performs all migrations. - func migrateAll() { + static func migrateAll(appState: AppState) { + let manager = MigrationManager(appState: appState) + do { try performAll(blocks: [ - migrate0_8_0, - migrate0_10_0, + manager.migrate0_8_0, + manager.migrate0_10_0, ]) } catch { logError(error) } let results = [ - migrate0_10_1(), + manager.migrate0_10_1(), ] for result in results { @@ -40,7 +42,7 @@ extension MigrationManager { } } - private func logError(_ error: any Error) { + private static func logError(_ error: any Error) { Logger.migration.error("Migration failed with error: \(error)") } } @@ -54,7 +56,7 @@ extension MigrationManager { guard !Defaults.bool(forKey: .hasMigrated0_8_0) else { return } - try performAll(blocks: [ + try MigrationManager.performAll(blocks: [ migrateHotkeys0_8_0, migrateControlItems0_8_0, migrateSections0_8_0, @@ -149,7 +151,7 @@ extension MigrationManager { // migrate the old autosave name to the new autosave name in UserDefaults StatusItemDefaults.migrate(key: .preferredPosition, from: autosaveName, to: identifier) - StatusItemDefaults.migrate(key: .isVisible, from: autosaveName, to: identifier) + StatusItemDefaults.migrate(key: .visible, from: autosaveName, to: identifier) // replace the old "controlItem" dictionary with the new one sectionDict["controlItem"] = controlItemDict @@ -181,7 +183,7 @@ extension MigrationManager { guard !Defaults.bool(forKey: .hasMigrated0_10_0) else { return } - try performAll(blocks: [ + try MigrationManager.performAll(blocks: [ migrateControlItems0_10_0, ]) Defaults.set(true, forKey: .hasMigrated0_10_0) @@ -223,12 +225,12 @@ extension MigrationManager { for identifier in ControlItem.Identifier.allCases { if - StatusItemDefaults[.isVisible, identifier.rawValue] == false, + StatusItemDefaults[.visible, identifier.rawValue] == false, StatusItemDefaults[.preferredPosition, identifier.rawValue] == nil { needsResetPreferredPositions = true } - StatusItemDefaults[.isVisible, identifier.rawValue] = nil + StatusItemDefaults[.visible, identifier.rawValue] = nil } if needsResetPreferredPositions { @@ -252,7 +254,7 @@ extension MigrationManager { extension MigrationManager { /// Performs every block in the given array, catching any thrown /// errors and rethrowing them as a combined error. - private func performAll(blocks: [() throws -> Void]) throws { + private static func performAll(blocks: [() throws -> Void]) throws { let results = blocks.map { block in Result(catching: block) } diff --git a/Ice/Utilities/ScreenState/ScreenState.swift b/Ice/Utilities/ScreenState/ScreenState.swift deleted file mode 100644 index aae9b29e..00000000 --- a/Ice/Utilities/ScreenState/ScreenState.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// ScreenState.swift -// Ice -// - -/// A type that represents the state of a screen. -enum ScreenState { - /// The screen is locked. - case locked - /// The screen is unlocked. - case unlocked - /// The screen saver is active. - case screenSaver -} - -extension ScreenState { - /// The current screen state. - static var current: ScreenState { - if ScreenStateManager.shared.screenSaverIsActive { - return .screenSaver - } - if ScreenStateManager.shared.screenIsLocked { - return .locked - } - return .unlocked - } -} diff --git a/Ice/Utilities/ScreenState/ScreenStateManager.swift b/Ice/Utilities/ScreenState/ScreenStateManager.swift deleted file mode 100644 index e2ff8bec..00000000 --- a/Ice/Utilities/ScreenState/ScreenStateManager.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// ScreenStateManager.swift -// Ice -// - -import Cocoa -import Combine - -final class ScreenStateManager { - static let shared = ScreenStateManager() - - private(set) var screenIsLocked = false - - private(set) var screenSaverIsActive = false - - private var cancellables = Set() - - private init() { - configureCancellables() - } - - static func setUpSharedManager() { - _ = shared - } - - private func configureCancellables() { - var c = Set() - - DistributedNotificationCenter.default() - .publisher(for: Notification.Name("com.apple.screenIsLocked")) - .sink { [weak self] _ in - self?.screenIsLocked = true - } - .store(in: &c) - - DistributedNotificationCenter.default() - .publisher(for: Notification.Name("com.apple.screenIsUnlocked")) - .sink { [weak self] _ in - self?.screenIsLocked = false - } - .store(in: &c) - - DistributedNotificationCenter.default() - .publisher(for: Notification.Name("com.apple.screensaver.didstart")) - .sink { [weak self] _ in - self?.screenSaverIsActive = true - } - .store(in: &c) - - DistributedNotificationCenter.default() - .publisher(for: Notification.Name("com.apple.screensaver.didstop")) - .sink { [weak self] _ in - self?.screenSaverIsActive = false - } - .store(in: &c) - - cancellables = c - } -} diff --git a/Ice/Utilities/StatusItemDefaults.swift b/Ice/Utilities/StatusItemDefaults.swift new file mode 100644 index 00000000..1e2b1e6b --- /dev/null +++ b/Ice/Utilities/StatusItemDefaults.swift @@ -0,0 +1,58 @@ +// +// StatusItemDefaults.swift +// Ice +// + +import Cocoa + +// MARK: - StatusItemDefaults + +/// Proxy getters and setters for a status item's user defaults values. +enum StatusItemDefaults { + /// Accesses the value associated with the specified key and autosave name. + static subscript(key: Key, autosaveName: String) -> Value? { + get { + let stringKey = key.stringKey(for: autosaveName) + return UserDefaults.standard.object(forKey: stringKey) as? Value + } + set { + let stringKey = key.stringKey(for: autosaveName) + return UserDefaults.standard.set(newValue, forKey: stringKey) + } + } + + /// Migrates the given status item defaults key from an old autosave name + /// to a new autosave name. + static func migrate(key: Key, from oldAutosaveName: String, to newAutosaveName: String) { + guard newAutosaveName != oldAutosaveName else { + return + } + Self[key, newAutosaveName] = Self[key, oldAutosaveName] + Self[key, oldAutosaveName] = nil + } +} + +// MARK: - StatusItemDefaults.Key + +extension StatusItemDefaults { + /// Keys used to look up user defaults values for status items. + struct Key { + /// The raw value of the key. + let rawValue: String + + /// Returns the full string key for the given autosave name. + func stringKey(for autosaveName: String) -> String { + return "NSStatusItem \(rawValue) \(autosaveName)" + } + } +} + +extension StatusItemDefaults.Key { + /// String key: "NSStatusItem Preferred Position autosaveName" + static let preferredPosition = Self(rawValue: "Preferred Position") +} + +extension StatusItemDefaults.Key { + /// String key: "NSStatusItem Visible autosaveName" + static let visible = Self(rawValue: "Visible") +} diff --git a/Ice/Utilities/StatusItemDefaults/StatusItemDefaults.swift b/Ice/Utilities/StatusItemDefaults/StatusItemDefaults.swift deleted file mode 100644 index 65c3ed74..00000000 --- a/Ice/Utilities/StatusItemDefaults/StatusItemDefaults.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// StatusItemDefaults.swift -// Ice -// - -import Foundation - -/// Proxy getters and setters for a status item's user default values. -enum StatusItemDefaults { - private static func stringKey(forKey key: StatusItemDefaultsKey, autosaveName: String) -> String { - return "NSStatusItem \(key.rawValue) \(autosaveName)" - } - - /// Accesses the value associated with the specified key and autosave name. - static subscript(key: StatusItemDefaultsKey, autosaveName: String) -> Value? { - get { - let key = stringKey(forKey: key, autosaveName: autosaveName) - return UserDefaults.standard.object(forKey: key) as? Value - } - set { - let key = stringKey(forKey: key, autosaveName: autosaveName) - UserDefaults.standard.set(newValue, forKey: key) - } - } - - /// Migrates the given status item defaults key from an old autosave name to a new autosave name. - static func migrate(key: StatusItemDefaultsKey, from oldAutosaveName: String, to newAutosaveName: String) { - guard newAutosaveName != oldAutosaveName else { - return - } - Self[key, newAutosaveName] = Self[key, oldAutosaveName] - Self[key, oldAutosaveName] = nil - } -} diff --git a/Ice/Utilities/StatusItemDefaults/StatusItemDefaultsKey.swift b/Ice/Utilities/StatusItemDefaults/StatusItemDefaultsKey.swift deleted file mode 100644 index feef44fa..00000000 --- a/Ice/Utilities/StatusItemDefaults/StatusItemDefaultsKey.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// StatusItemDefaultsKey.swift -// Ice -// - -import CoreGraphics - -/// Keys used to look up user defaults for status items. -struct StatusItemDefaultsKey { - let rawValue: String -} - -extension StatusItemDefaultsKey { - static let preferredPosition = StatusItemDefaultsKey(rawValue: "Preferred Position") -} - -extension StatusItemDefaultsKey { - static let isVisible = StatusItemDefaultsKey(rawValue: "Visible") -}