macoc/Sources/CapswitchApp/StatusBarController.swift

129 lines
3.5 KiB
Swift

import AppKit
import Foundation
final class StatusBarController: NSObject, NSMenuDelegate {
private let inputController: MacOSInputController
private let statusItem: NSStatusItem
private let menu = NSMenu()
private let currentLayoutItem = NSMenuItem(
title: "",
action: nil,
keyEquivalent: ""
)
private let permissionItem = NSMenuItem(
title: "",
action: #selector(openAccessibilitySettings),
keyEquivalent: ""
)
private let pauseItem = NSMenuItem(
title: "",
action: #selector(togglePaused),
keyEquivalent: ""
)
private var refreshTimer: Timer?
init(inputController: MacOSInputController = MacOSInputController()) {
self.inputController = inputController
self.statusItem = NSStatusBar.system.statusItem(
withLength: NSStatusItem.variableLength
)
super.init()
configureMenu()
inputController.onStateChanged = { [weak self] in
self?.update()
}
refreshTimer = Timer.scheduledTimer(
withTimeInterval: 1,
repeats: true
) { [weak self] _ in
self?.refreshController()
}
refreshController()
}
deinit {
refreshTimer?.invalidate()
inputController.stop()
statusItem.menu = nil
NSStatusBar.system.removeStatusItem(statusItem)
}
private func configureMenu() {
menu.delegate = self
menu.addItem(currentLayoutItem)
menu.addItem(NSMenuItem.separator())
menu.addItem(pauseItem)
menu.addItem(permissionItem)
menu.addItem(NSMenuItem.separator())
let quitItem = NSMenuItem(
title: "Quit Capswitch",
action: #selector(quit),
keyEquivalent: "q"
)
menu.addItem(quitItem)
for item in [pauseItem, permissionItem, quitItem] {
item.target = self
}
statusItem.menu = menu
statusItem.button?.toolTip = "Capswitch"
}
private func refreshController() {
if inputController.accessibilityTrusted,
!inputController.isRunning {
try? inputController.start()
}
update()
}
private func update() {
let shortName = inputController.currentInputSourceShortName
statusItem.button?.title = shortName
statusItem.button?.toolTip = "Capswitch - \(inputController.currentInputSourceName)"
currentLayoutItem.title =
"Current layout: \(inputController.currentInputSourceName)"
pauseItem.title = inputController.isPaused
? "Resume switching"
: "Pause switching"
pauseItem.state = inputController.isPaused ? .on : .off
if inputController.accessibilityTrusted {
permissionItem.title = inputController.isRunning
? "Accessibility: Granted"
: "Accessibility: Granted (tap stopped)"
} else {
permissionItem.title = "Grant Accessibility permission…"
}
for item in [currentLayoutItem, permissionItem, pauseItem] {
item.target = self
}
}
func menuWillOpen(_ menu: NSMenu) {
refreshController()
}
@objc private func togglePaused() {
inputController.setPaused(!inputController.isPaused)
update()
}
@objc private func openAccessibilitySettings() {
inputController.openAccessibilitySettings()
}
@objc private func quit() {
NSApp.terminate(nil)
}
}