diff --git a/Clocker/AppDelegate.swift b/Clocker/AppDelegate.swift index 02c31e2..c2dae4a 100644 --- a/Clocker/AppDelegate.swift +++ b/Clocker/AppDelegate.swift @@ -10,13 +10,8 @@ open class AppDelegate: NSObject, NSApplicationDelegate { private lazy var floatingWindow = FloatingWindowController.shared() internal lazy var panelController = PanelController(windowNibName: .panel) private var statusBarHandler: StatusItemHandler! - private var panelObserver: NSKeyValueObservation? private let store: VersionUpdateHandler = VersionUpdateHandler(with: DataStore.shared()) - deinit { - panelObserver?.invalidate() - } - override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) { if let path = keyPath, path == PreferencesConstants.hotKeyPathIdentifier { let hotKeyCenter = PTHotKeyCenter.shared() @@ -178,7 +173,7 @@ open class AppDelegate: NSObject, NSApplicationDelegate { alert.runModal() } - @IBAction func ping(_ sender: Any) { + @IBAction func ping(_ sender: NSButton) { togglePanel(sender) } @@ -234,16 +229,16 @@ open class AppDelegate: NSObject, NSApplicationDelegate { NSApp.terminate(nil) } - @IBAction open func togglePanel(_: Any) { + @IBAction open func togglePanel(_ sender: NSButton) { + Logger.info("Toggle Panel called with sender state \(sender.state.rawValue)") let displayMode = UserDefaults.standard.integer(forKey: CLShowAppInForeground) if displayMode == 1 { // No need to call NSApp.activate here since `showFloatingWindow` takes care of this showFloatingWindow() } else { - setupPanelObserverIfNeeeded() panelController.showWindow(nil) - panelController.setActivePanel(newValue: !panelController.hasActivePanelGetter()) + panelController.setActivePanel(newValue: sender.state == .on) NSApp.activate(ignoringOtherApps: true) } } @@ -263,12 +258,4 @@ open class AppDelegate: NSObject, NSApplicationDelegate { open func invalidateMenubarTimer(_ showIcon: Bool) { statusBarHandler.invalidateTimer(showIcon: showIcon, isSyncing: true) } - - private func setupPanelObserverIfNeeeded() { - if panelObserver == nil { - panelObserver = panelController.observe(\.hasActivePanel, options: [.new]) { obj, _ in - self.statusBarHandler.setHasActiveIcon(obj.hasActivePanelGetter()) - } - } - } } diff --git a/Clocker/ClockerUnitTests/AppDelegateTests.swift b/Clocker/ClockerUnitTests/AppDelegateTests.swift index a95b1ce..494679e 100644 --- a/Clocker/ClockerUnitTests/AppDelegateTests.swift +++ b/Clocker/ClockerUnitTests/AppDelegateTests.swift @@ -86,11 +86,11 @@ class AppDelegateTests: XCTestCase { let subject = NSApplication.shared.delegate as? AppDelegate subject?.invalidateMenubarTimer(true) let statusItemHandler = subject?.statusItemForPanel() - XCTAssertNil(statusItemHandler?.statusItem.view) - XCTAssertEqual(statusItemHandler?.statusItem.title, CLEmptyString) + XCTAssertEqual(statusItemHandler?.statusItem.button?.subviews, []) + XCTAssertEqual(statusItemHandler?.statusItem.button?.title, CLEmptyString) XCTAssertEqual(statusItemHandler?.statusItem.button?.image?.name(), "LightModeIcon") XCTAssertEqual(statusItemHandler?.statusItem.button?.imagePosition, .imageOnly) - XCTAssertEqual(statusItemHandler?.statusItem.toolTip, "Clocker") + XCTAssertEqual(statusItemHandler?.statusItem.button?.toolTip, "Clocker") } func testCompactModeMenubarSetup() { @@ -109,7 +109,7 @@ class AppDelegateTests: XCTestCase { subject?.setupMenubarTimer() let statusItemHandler = subject?.statusItemForPanel() - XCTAssertNotNil(statusItemHandler?.statusItem.view) // This won't be nil for compact mode + XCTAssertNotNil(statusItemHandler?.statusItem.button) // This won't be nil for compact mode DataStore.shared().setTimezones(olderTimezones) } @@ -140,7 +140,7 @@ class AppDelegateTests: XCTestCase { subject?.setupMenubarTimer() - XCTAssertNil(subject?.statusItemForPanel().statusItem.view) // This will be nil for standard mode + XCTAssertEqual(subject?.statusItemForPanel().statusItem.button?.subviews.isEmpty, true) // This will be nil for standard mode UserDefaults.standard.set(0, forKey: CLMenubarCompactMode) // Set the menubar mode back to compact } diff --git a/Clocker/Overall App/Foundation + Additions.swift b/Clocker/Overall App/Foundation + Additions.swift index dd271c6..e3fc53a 100644 --- a/Clocker/Overall App/Foundation + Additions.swift +++ b/Clocker/Overall App/Foundation + Additions.swift @@ -61,11 +61,7 @@ extension NSKeyedArchiver { static func clocker_archive(with object: Any) -> Data? { if #available(macOS 10.14, *) { - return try! NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: true) - } - - if #available(macOS 10.13, *) { - return NSKeyedArchiver.archivedData(withRootObject: object) + return try? NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: true) } return nil diff --git a/Clocker/Panel/PanelController.swift b/Clocker/Panel/PanelController.swift index cc87e97..36df64c 100644 --- a/Clocker/Panel/PanelController.swift +++ b/Clocker/Panel/PanelController.swift @@ -143,8 +143,8 @@ class PanelController: ParentPanelController { return } - var statusBackgroundWindow = appDelegate.statusItemForPanel().statusItem.view?.window - var statusView = appDelegate.statusItemForPanel().statusItem.view + var statusBackgroundWindow = appDelegate.statusItemForPanel().statusItem.button?.window + var statusView = appDelegate.statusItemForPanel().statusItem.button // This below is a better way than actually checking if the menubar compact mode is set. if statusBackgroundWindow == nil || statusView == nil { @@ -407,7 +407,7 @@ extension PanelController: NSWindowDelegate { setActivePanel(newValue: false) } if let appDelegate = NSApplication.shared.delegate as? AppDelegate { - appDelegate.statusItemForPanel().hasActiveIcon = false + appDelegate.statusItemForPanel().statusItem.button?.state = .off } } } diff --git a/Clocker/Preferences/General/PreferencesDataSource.swift b/Clocker/Preferences/General/PreferencesDataSource.swift index 56544eb..08dfff5 100644 --- a/Clocker/Preferences/General/PreferencesDataSource.swift +++ b/Clocker/Preferences/General/PreferencesDataSource.swift @@ -66,11 +66,13 @@ extension PreferencesDataSource: NSTableViewDelegate { return false } - guard let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: data) as? IndexSet, let first = rowIndexes.first else { + guard let rowIndexes = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSIndexSet.self, from: data) else { assertionFailure("Row was unexpectedly nil") return false } + let first = rowIndexes.firstIndex + let currentObject = newOrder[first] newOrder.remove(at: first) diff --git a/Clocker/Preferences/General/PreferencesViewController.swift b/Clocker/Preferences/General/PreferencesViewController.swift index 61bc43c..d6ed874 100644 --- a/Clocker/Preferences/General/PreferencesViewController.swift +++ b/Clocker/Preferences/General/PreferencesViewController.swift @@ -297,7 +297,7 @@ class PreferencesViewController: ParentViewController { } } - @objc func ping(_ sender: Any) { + @objc func ping(_ sender: NSButton) { guard let delegate = NSApplication.shared.delegate as? AppDelegate else { return } diff --git a/Clocker/Preferences/Menu Bar/StatusItemHandler.swift b/Clocker/Preferences/Menu Bar/StatusItemHandler.swift index a66f2e1..f403d6d 100644 --- a/Clocker/Preferences/Menu Bar/StatusItemHandler.swift +++ b/Clocker/Preferences/Menu Bar/StatusItemHandler.swift @@ -17,8 +17,8 @@ class StatusItemHandler: NSObject { var statusItem: NSStatusItem = { let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) - statusItem.toolTip = "Clocker" - statusItem.highlightMode = false + statusItem.button?.toolTip = "Clocker" + (statusItem.button?.cell as? NSButtonCell)?.highlightsBy = NSCell.StyleMask(rawValue: 0) return statusItem }() @@ -43,7 +43,7 @@ class StatusItemHandler: NSObject { // Do some cleanup switch oldValue { case .compactText: - statusItem.view = nil + statusItem.button?.subviews = [] statusContainerView = nil case .standardText: statusItem.button?.title = CLEmptyString @@ -98,7 +98,7 @@ class StatusItemHandler: NSObject { } } - statusItem.target = self + statusItem.button?.target = self statusItem.autosaveName = NSStatusItem.AutosaveName("ClockerStatusItem") setSelector() } @@ -151,8 +151,10 @@ class StatusItemHandler: NSObject { store: store, showUpcomingEventView: upcomingEventView, bufferContainerWidth: bufferCalculatedWidth()) - statusItem.view = statusContainerView - statusItem.view?.window?.backgroundColor = NSColor.clear + statusContainerView?.wantsLayer = true + statusItem.button?.addSubview(statusContainerView!) + statusItem.button?.frame = statusContainerView!.bounds + statusItem.button?.subviews.first?.window?.backgroundColor = NSColor.clear } // This is called when the Apple interface style pre-Mojave is changed. @@ -169,7 +171,7 @@ class StatusItemHandler: NSObject { hasActiveIcon = value } - @objc func menubarIconClicked(_ sender: Any) { + @objc func menubarIconClicked(_ sender: NSStatusBarButton) { guard let mainDelegate = NSApplication.shared.delegate as? AppDelegate else { return } @@ -340,8 +342,8 @@ class StatusItemHandler: NSObject { } private func setClockerIcon() { - if statusItem.view != nil { - statusItem.view = nil + if statusItem.button?.subviews.isEmpty == false { + statusItem.button?.subviews = [] } if statusItem.button?.image?.name() == NSImage.Name.menubarIcon { @@ -351,7 +353,7 @@ class StatusItemHandler: NSObject { statusItem.button?.title = CLEmptyString statusItem.button?.image = NSImage(named: .menubarIcon) statusItem.button?.imagePosition = .imageOnly - statusItem.toolTip = "Clocker" + statusItem.button?.toolTip = "Clocker" } private func setupForStandardText() { diff --git a/Clocker/Preferences/Menu Bar/StatusItemView.swift b/Clocker/Preferences/Menu Bar/StatusItemView.swift index b90dca3..2723a62 100644 --- a/Clocker/Preferences/Menu Bar/StatusItemView.swift +++ b/Clocker/Preferences/Menu Bar/StatusItemView.swift @@ -111,7 +111,7 @@ class StatusItemView: NSView { NSLayoutConstraint.activate([ locationView.leadingAnchor.constraint(equalTo: leadingAnchor), locationView.trailingAnchor.constraint(equalTo: trailingAnchor), - locationView.topAnchor.constraint(equalTo: topAnchor, constant: 7), + locationView.topAnchor.constraint(equalTo: topAnchor, constant: 0), locationView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.35), ]) @@ -138,15 +138,6 @@ class StatusItemView: NSView { required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - - override func mouseDown(with event: NSEvent) { - super.mouseDown(with: event) - guard let mainDelegate = NSApplication.shared.delegate as? AppDelegate else { - return - } - - mainDelegate.togglePanel(event) - } } extension StatusItemView: StatusItemViewConforming { diff --git a/Clocker/Preferences/Menu Bar/UpcomingEventStatusItemView.swift b/Clocker/Preferences/Menu Bar/UpcomingEventStatusItemView.swift index d5abbd2..70ac110 100644 --- a/Clocker/Preferences/Menu Bar/UpcomingEventStatusItemView.swift +++ b/Clocker/Preferences/Menu Bar/UpcomingEventStatusItemView.swift @@ -85,15 +85,6 @@ class UpcomingEventStatusItemView: NSView { nextEventField.attributedStringValue = NSAttributedString(string: "Next Event", attributes: textFontAttributes) etaField.attributedStringValue = NSAttributedString(string: metadata, attributes: timeAttributes) } - - override func mouseDown(with event: NSEvent) { - super.mouseDown(with: event) - guard let mainDelegate = NSApplication.shared.delegate as? AppDelegate else { - return - } - - mainDelegate.togglePanel(event) - } } extension UpcomingEventStatusItemView: StatusItemViewConforming {