|
|
@ -32,14 +32,6 @@ class StatusItemHandler: NSObject { |
|
|
|
|
|
|
|
|
|
|
|
private var userNotificationsDidChangeNotif: NSObjectProtocol? |
|
|
|
private var userNotificationsDidChangeNotif: NSObjectProtocol? |
|
|
|
|
|
|
|
|
|
|
|
/// Observer that tracks if the front-level application (not window) updates. This might trigger a status bar reconstruction. |
|
|
|
|
|
|
|
private var frontMostApplicationObserver: NSKeyValueObservation? |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Delay timer that co-ordinates the status bar reconstruction |
|
|
|
|
|
|
|
private var timer: Timer? |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private var hasSystemHiddenClocker = false |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Current State might be set twice when the user first launches an app. |
|
|
|
// Current State might be set twice when the user first launches an app. |
|
|
|
// First, when StatusItemHandler() is instantiated in AppDelegate |
|
|
|
// First, when StatusItemHandler() is instantiated in AppDelegate |
|
|
|
// Second, when AppDelegate.fetchLocalTimezone() is called triggering a customLabel didSet. |
|
|
|
// Second, when AppDelegate.fetchLocalTimezone() is called triggering a customLabel didSet. |
|
|
@ -61,7 +53,6 @@ class StatusItemHandler: NSObject { |
|
|
|
switch currentState { |
|
|
|
switch currentState { |
|
|
|
case .compactText: |
|
|
|
case .compactText: |
|
|
|
setupForCompactTextMode() |
|
|
|
setupForCompactTextMode() |
|
|
|
|
|
|
|
|
|
|
|
case .standardText: |
|
|
|
case .standardText: |
|
|
|
setupForStandardTextMode() |
|
|
|
setupForStandardTextMode() |
|
|
|
case .icon: |
|
|
|
case .icon: |
|
|
@ -77,10 +68,10 @@ class StatusItemHandler: NSObject { |
|
|
|
|
|
|
|
|
|
|
|
setupStatusItem() |
|
|
|
setupStatusItem() |
|
|
|
setupNotificationObservers() |
|
|
|
setupNotificationObservers() |
|
|
|
startObservingFrontmostApplication() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private func getMenubarState() -> MenubarState { |
|
|
|
func setupStatusItem() { |
|
|
|
|
|
|
|
// Let's figure out the initial menubar state |
|
|
|
var menubarState = MenubarState.icon |
|
|
|
var menubarState = MenubarState.icon |
|
|
|
|
|
|
|
|
|
|
|
let shouldTextBeDisplayed = DataStore.shared().menubarTimezones()?.isEmpty ?? true |
|
|
|
let shouldTextBeDisplayed = DataStore.shared().menubarTimezones()?.isEmpty ?? true |
|
|
@ -92,12 +83,9 @@ class StatusItemHandler: NSObject { |
|
|
|
menubarState = .standardText |
|
|
|
menubarState = .standardText |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return menubarState |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func setupStatusItem() { |
|
|
|
|
|
|
|
// Initial state has been figured out. Time to set it! |
|
|
|
// Initial state has been figured out. Time to set it! |
|
|
|
currentState = getMenubarState() |
|
|
|
currentState = menubarState |
|
|
|
|
|
|
|
|
|
|
|
func setSelector() { |
|
|
|
func setSelector() { |
|
|
|
if #available(macOS 10.14, *) { |
|
|
|
if #available(macOS 10.14, *) { |
|
|
@ -138,12 +126,12 @@ class StatusItemHandler: NSObject { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private func constructCompactView(_ forceSet: Bool = false) { |
|
|
|
private func constructCompactView() { |
|
|
|
parentView = nil |
|
|
|
parentView = nil |
|
|
|
|
|
|
|
|
|
|
|
let menubarTimezones = retrieveSyncedMenubarTimezones() |
|
|
|
let menubarTimezones = retrieveSyncedMenubarTimezones() |
|
|
|
|
|
|
|
|
|
|
|
if menubarTimezones.isEmpty || forceSet { |
|
|
|
if menubarTimezones.isEmpty { |
|
|
|
currentState = .icon |
|
|
|
currentState = .icon |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
@ -262,12 +250,6 @@ class StatusItemHandler: NSObject { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func refresh() { |
|
|
|
func refresh() { |
|
|
|
if statusBarVisibilityStatus() == false { |
|
|
|
|
|
|
|
hasSystemHiddenClocker = true |
|
|
|
|
|
|
|
setClockerIcon() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if currentState == .compactText { |
|
|
|
if currentState == .compactText { |
|
|
|
updateCompactMenubar() |
|
|
|
updateCompactMenubar() |
|
|
|
updateMenubar() |
|
|
|
updateMenubar() |
|
|
@ -373,57 +355,4 @@ class StatusItemHandler: NSObject { |
|
|
|
constructCompactView() |
|
|
|
constructCompactView() |
|
|
|
updateMenubar() |
|
|
|
updateMenubar() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// MARK: Front-end application observer |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private func statusBarVisibilityStatus() -> Bool { |
|
|
|
|
|
|
|
guard let windowInfoList = CGWindowListCopyWindowInfo(CGWindowListOption.optionOnScreenOnly, kCGNullWindowID) as NSArray? as? [[String: AnyObject]] else { |
|
|
|
|
|
|
|
print("Failed getting the status bar's visibility") |
|
|
|
|
|
|
|
return false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// collect all status bar icons x positions |
|
|
|
|
|
|
|
for windowInfo in windowInfoList { |
|
|
|
|
|
|
|
let windowOwner = windowInfo[kCGWindowOwnerName as String] as? String ?? "No Window Name" |
|
|
|
|
|
|
|
let isOnScreen = windowInfo[kCGWindowIsOnscreen as String] as? NSNumber ?? 0 |
|
|
|
|
|
|
|
let level = windowInfo[kCGWindowLayer as String] as? Int ?? -1 // Check the level since it can be the preferences window |
|
|
|
|
|
|
|
if windowOwner == "Clocker", level == 25 { |
|
|
|
|
|
|
|
return isOnScreen.boolValue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clocker is not in the windows list; return false |
|
|
|
|
|
|
|
return false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private func startObservingFrontmostApplication() { |
|
|
|
|
|
|
|
if getMenubarState() == .icon { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontMostApplicationObserver = NSWorkspace.shared.observe(\.frontmostApplication, options: [.new, .old]) { [weak self] _, change in |
|
|
|
|
|
|
|
guard change.newValue != nil, change.oldValue != nil, let localSelf = self else { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
localSelf.reconstructStatusBarIfNeccesary() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private func reconstructStatusBarIfNeccesary() { |
|
|
|
|
|
|
|
if let time = self.timer, time.isValid { |
|
|
|
|
|
|
|
time.invalidate() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { [weak self] _ in |
|
|
|
|
|
|
|
guard let localSelf = self else { return } |
|
|
|
|
|
|
|
if localSelf.statusBarVisibilityStatus() == false { |
|
|
|
|
|
|
|
localSelf.constructCompactView(true) |
|
|
|
|
|
|
|
localSelf.hasSystemHiddenClocker = true |
|
|
|
|
|
|
|
localSelf.statusItem.target = self |
|
|
|
|
|
|
|
localSelf.statusItem.button?.action = #selector(localSelf.menubarIconClicked(_:)) |
|
|
|
|
|
|
|
} else if localSelf.hasSystemHiddenClocker { |
|
|
|
|
|
|
|
localSelf.constructCompactView() |
|
|
|
|
|
|
|
localSelf.hasSystemHiddenClocker = false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|