From 53d58190ca7e1513ceeae70a960ec0046e56c51a Mon Sep 17 00:00:00 2001 From: Jordan Baird Date: Wed, 28 Aug 2024 20:17:20 -0600 Subject: [PATCH] Various reworks * Remove `ObservableObject` conformance from `ControlItem` and `MenuBarSection` * Comment changes * Misc other minor reworks --- Ice/ControlItem/ControlItem.swift | 2 +- Ice/MenuBar/MenuBarManager.swift | 61 +++++++----------- Ice/MenuBar/MenuBarSection.swift | 100 ++++++++++++------------------ 3 files changed, 61 insertions(+), 102 deletions(-) diff --git a/Ice/ControlItem/ControlItem.swift b/Ice/ControlItem/ControlItem.swift index da257903..f000f0e9 100644 --- a/Ice/ControlItem/ControlItem.swift +++ b/Ice/ControlItem/ControlItem.swift @@ -9,7 +9,7 @@ import OSLog /// A status item that controls the a section in the menu bar. @MainActor -final class ControlItem: ObservableObject { +final class ControlItem { enum Identifier: String, Hashable, CaseIterable { case iceIcon = "SItem" case hidden = "HItem" diff --git a/Ice/MenuBar/MenuBarManager.swift b/Ice/MenuBar/MenuBarManager.swift index c4163020..61e2c4c8 100644 --- a/Ice/MenuBar/MenuBarManager.swift +++ b/Ice/MenuBar/MenuBarManager.swift @@ -24,27 +24,22 @@ final class MenuBarManager: ObservableObject { @Published private(set) var isMenuBarHiddenBySystemUserDefaults = false private(set) weak var appState: AppState? - - private(set) var sections = [MenuBarSection]() + private var cancellables = Set() let appearanceManager: MenuBarAppearanceManager - let iceBarPanel: IceBarPanel private let encoder = JSONEncoder() - private let decoder = JSONDecoder() private var isHidingApplicationMenus = false - private var canUpdateAverageColor = false - private var cancellables = Set() + private(set) var sections = [MenuBarSection]() /// The currently shown section. var shownSection: MenuBarSection? { - // filter out the visible section; - // if multiple sections are shown, return the last one + // Filter out the visible section. If multiple sections are shown, return the last one. sections.lazy .filter { section in section.name != .visible @@ -71,7 +66,7 @@ final class MenuBarManager: ObservableObject { /// Performs the initial setup of the menu bar's section list. private func initializeSections() { - // make sure initialization can only happen once + // Make sure initialization can only happen once. guard sections.isEmpty else { Logger.menuBarManager.warning("Sections already initialized") return @@ -83,7 +78,7 @@ final class MenuBarManager: ObservableObject { MenuBarSection(name: .alwaysHidden), ] - // assign the global app state to each section + // Assign the global app state to each section. if let appState { for section in sections { section.assignAppState(appState) @@ -123,7 +118,7 @@ final class MenuBarManager: ObservableObject { .store(in: &c) } - // handle focusedApp rehide strategy + // Handle the `focusedApp` rehide strategy. NSWorkspace.shared.publisher(for: \.frontmostApplication) .sink { [weak self] _ in if @@ -173,7 +168,7 @@ final class MenuBarManager: ObservableObject { } .store(in: &c) - // hide application menus when a section is shown (if applicable) + // Hide application menus when a section is shown (if applicable). Publishers.MergeMany(sections.map { $0.controlItem.$state }) .removeDuplicates() .receive(on: DispatchQueue.main) @@ -185,11 +180,11 @@ final class MenuBarManager: ObservableObject { return } - // don't continue if: - // * the "HideApplicationMenus" setting isn't enabled - // * the menu bar is hidden by the system - // * the active space is fullscreen - // * the settings window is visible + // Don't continue if: + // * The "HideApplicationMenus" setting isn't enabled. + // * The menu bar is hidden by the system. + // * The active space is fullscreen. + // * The settings window is visible. guard appState.settingsManager.advancedSettingsManager.hideApplicationMenus, !isMenuBarHiddenBySystem, @@ -206,25 +201,25 @@ final class MenuBarManager: ObservableObject { let displayID = screen.displayID - // get the application menu frame for the display + // Get the application menu frame for the display. guard let applicationMenuFrame = getApplicationMenuFrame(for: displayID) else { return } let items = MenuBarItem.getMenuBarItems(on: displayID, using: .coreGraphics, onScreenOnly: true, sortingBy: .orderInMenuBar) - // get the leftmost item on the screen; the application menu should - // be hidden if the item's minX is close to the maxX of the menu + // Get the leftmost item on the screen. The application menu should + // be hidden if the item's minX is close to the maxX of the menu. guard let leftmostItem = items.min(by: { $0.frame.minX < $1.frame.minX }) else { return } - // offset the leftmost item's minX by its width to give ourselves - // a little wiggle room + // Offset the leftmost item's minX by its width to give ourselves + // a little wiggle room. let offsetMinX = leftmostItem.frame.minX - leftmostItem.frame.width - // if the offset value is less than or equal to the maxX of the - // application menu frame, activate the app to hide the menu + // If the offset value is less than or equal to the maxX of the + // application menu frame, activate the app to hide the menu. if offsetMinX <= applicationMenuFrame.maxX + 15 { hideApplicationMenus() } @@ -234,15 +229,6 @@ final class MenuBarManager: ObservableObject { } .store(in: &c) - // propagate changes from all sections - for section in sections { - section.objectWillChange - .sink { [weak self] in - self?.objectWillChange.send() - } - .store(in: &c) - } - cancellables = c } @@ -329,10 +315,9 @@ final class MenuBarManager: ObservableObject { return nil } - // the Accessibility API returns the menu bar for the active screen, regardless of - // the display origin used; this workaround prevents an incorrect frame from being - // returned for inactive displays in multi-display setups where one display has a - // notch + // The Accessibility API returns the menu bar for the active screen, regardless of the + // display origin used. This workaround prevents an incorrect frame from being returned + // for inactive displays in multi-display setups where one display has a notch. if let mainScreen = NSScreen.main, let thisScreen = NSScreen.screens.first(where: { $0.displayID == displayID }), @@ -416,10 +401,8 @@ final class MenuBarManager: ObservableObject { } } -// MARK: MenuBarManager: BindingExposable extension MenuBarManager: BindingExposable { } -// MARK: - Logger private extension Logger { static let menuBarManager = Logger(category: "MenuBarManager") } diff --git a/Ice/MenuBar/MenuBarSection.swift b/Ice/MenuBar/MenuBarSection.swift index fa556a0c..1d427e71 100644 --- a/Ice/MenuBar/MenuBarSection.swift +++ b/Ice/MenuBar/MenuBarSection.swift @@ -4,22 +4,40 @@ // import Cocoa -import Combine import OSLog /// A representation of a section in a menu bar. @MainActor -final class MenuBarSection: ObservableObject { - let name: Name +final class MenuBarSection { + /// The name of a menu bar section. + enum Name: CaseIterable { + case visible + case hidden + case alwaysHidden + + var menuString: String { + switch self { + case .visible: "Visible" + case .hidden: "Hidden" + case .alwaysHidden: "Always Hidden" + } + } + var logString: String { + switch self { + case .visible: "visible section" + case .hidden: "hidden section" + case .alwaysHidden: "always hidden section" + } + } + } + + let name: Name let controlItem: ControlItem private var rehideTimer: Timer? - private var rehideMonitor: UniversalEventMonitor? - private var cancellables = Set() - private var useIceBar: Bool { appState?.settingsManager.generalSettingsManager.useIceBar ?? false } @@ -52,6 +70,7 @@ final class MenuBarSection: ObservableObject { appState?.menuBarManager } + /// A Boolean value that indicates whether the section is hidden. var isHidden: Bool { if useIceBar { if controlItem.state == .showItems { @@ -78,44 +97,29 @@ final class MenuBarSection: ObservableObject { } } + /// A Boolean value that indicates whether the section is enabled. var isEnabled: Bool { if case .visible = name { - // visible section should always be enabled + // The visible section should always be enabled. return true } return controlItem.isAddedToMenuBar } + /// Creates a section with the given name and control item. init(name: Name, controlItem: ControlItem) { self.name = name self.controlItem = controlItem - configureCancellables() } - /// Creates a menu bar section with the given name. + /// Creates a section with the given name. convenience init(name: Name) { - let controlItem = switch name { - case .visible: - ControlItem(identifier: .iceIcon) - case .hidden: - ControlItem(identifier: .hidden) - case .alwaysHidden: - ControlItem(identifier: .alwaysHidden) + let identifier: ControlItem.Identifier = switch name { + case .visible: .iceIcon + case .hidden: .hidden + case .alwaysHidden: .alwaysHidden } - self.init(name: name, controlItem: controlItem) - } - - private func configureCancellables() { - var c = Set() - - // propagate changes from the section's control item - controlItem.objectWillChange - .sink { [weak self] in - self?.objectWillChange.send() - } - .store(in: &c) - - cancellables = c + self.init(name: name, controlItem: ControlItem(identifier: identifier)) } /// Assigns the section's app state. @@ -127,7 +131,7 @@ final class MenuBarSection: ObservableObject { self.appState = appState } - /// Shows the status items in the section. + /// Shows the section. func show() { guard let menuBarManager, @@ -136,7 +140,7 @@ final class MenuBarSection: ObservableObject { return } guard controlItem.isAddedToMenuBar else { - // section is disabled + // The section is disabled. return } switch name { @@ -187,7 +191,7 @@ final class MenuBarSection: ObservableObject { startRehideChecks() } - /// Hides the status items in the section. + /// Hides the section. func hide() { guard let appState, @@ -229,7 +233,7 @@ final class MenuBarSection: ObservableObject { stopRehideChecks() } - /// Toggles the visibility of the status items in the section. + /// Toggles the visibility of the section. func toggle() { if isHidden { show() @@ -298,36 +302,8 @@ final class MenuBarSection: ObservableObject { } } -// MARK: MenuBarSection: BindingExposable extension MenuBarSection: BindingExposable { } -// MARK: MenuBarSection.Name -extension MenuBarSection { - /// The name of a menu bar section. - enum Name: CaseIterable { - case visible - case hidden - case alwaysHidden - - var menuString: String { - switch self { - case .visible: "Visible" - case .hidden: "Hidden" - case .alwaysHidden: "Always-Hidden" - } - } - - var logString: String { - switch self { - case .visible: "visible section" - case .hidden: "hidden section" - case .alwaysHidden: "always-hidden section" - } - } - } -} - -// MARK: - Logger private extension Logger { static let menuBarSection = Logger(category: "MenuBarSection") }