-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathStatusBarController.swift
More file actions
141 lines (118 loc) · 6.63 KB
/
Copy pathStatusBarController.swift
File metadata and controls
141 lines (118 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import Cocoa
/// Owns the menu-bar `NSStatusItem`. Builds a compact menu with:
/// • Show Window — opens the main UI (settings + quick-convert + hotkey)
/// • Convert focused text / clean clipboard
/// • Force half→full / full→half
/// • About
/// • Quit
///
/// The "Preferences…" entry is gone — settings now live inside the main window.
final class StatusBarController: NSObject {
private let statusItem: NSStatusItem
private let showMainWindowHandler: () -> Void
private let openAboutHandler: () -> Void
init(showMainWindow: @escaping () -> Void, openAbout: @escaping () -> Void) {
self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
self.showMainWindowHandler = showMainWindow
self.openAboutHandler = openAbout
super.init()
configureButton()
statusItem.menu = buildMenu()
// Our pref is the single source of truth for visibility. AppKit also
// persists isVisible under its own defaults key (per autosaveName);
// this unconditional assignment overrides whatever it restored.
statusItem.isVisible = PreferencesStore.shared.showMenuBarIcon
NotificationCenter.default.addObserver(self,
selector: #selector(handleHotKeyChanged),
name: PreferencesStore.hotKeyChangedNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(handleMenuBarIconChanged),
name: PreferencesStore.menuBarIconChangedNotification,
object: nil)
}
deinit { NotificationCenter.default.removeObserver(self) }
func refresh() { statusItem.menu = buildMenu() }
private func configureButton() {
guard let button = statusItem.button else { return }
// SF Symbol — auto template image, follows menu-bar tint, has Dark Mode variants.
// `textformat.size` is literally "Aa" — same visual idiom as the app icon.
if let image = NSImage(systemSymbolName: "textformat.size",
accessibilityDescription: Bundle.main.appName) {
image.isTemplate = true
button.image = image
} else {
button.title = "Aa"
}
button.toolTip = NSLocalizedString("statusbar.tooltip",
value: "halfFull — transform text and clean the clipboard",
comment: "")
}
private func buildMenu() -> NSMenu {
let menu = NSMenu()
let prefs = PreferencesStore.shared
// 1. Show Window — the primary entry now that settings live in the main UI.
let show = NSMenuItem(title: NSLocalizedString("menu.showWindow",
value: "Show Window",
comment: ""),
action: #selector(showWindow), keyEquivalent: "")
show.target = self
menu.addItem(show)
menu.addItem(.separator())
// 2. Convert action — shows the bound hotkey trailing for muscle-memory training.
let convertTitle = String(format: NSLocalizedString("menu.convert",
value: "Convert (%@)",
comment: ""),
prefs.hotKey.symbolicDescription)
let convert = NSMenuItem(title: convertTitle,
action: #selector(convertPreferred),
keyEquivalent: "")
convert.target = self
menu.addItem(convert)
let cleanTitle = String(format: NSLocalizedString("menu.cleanClipboard",
value: "Clean Clipboard (%@)",
comment: ""),
prefs.hotKey(for: .clipboard).symbolicDescription)
let clean = NSMenuItem(title: cleanTitle,
action: #selector(cleanClipboard),
keyEquivalent: "")
clean.target = self
menu.addItem(clean)
let toFull = NSMenuItem(title: NSLocalizedString("menu.forceFullWidth",
value: "Force half → full-width",
comment: ""),
action: #selector(forceFullWidth), keyEquivalent: "")
toFull.target = self
menu.addItem(toFull)
let toHalf = NSMenuItem(title: NSLocalizedString("menu.forceHalfWidth",
value: "Force full → half-width",
comment: ""),
action: #selector(forceHalfWidth), keyEquivalent: "")
toHalf.target = self
menu.addItem(toHalf)
menu.addItem(.separator())
let about = NSMenuItem(title: NSLocalizedString("menu.about",
value: "About halfFull",
comment: ""),
action: #selector(openAbout), keyEquivalent: "")
about.target = self
menu.addItem(about)
let quit = NSMenuItem(title: NSLocalizedString("menu.quit", value: "Quit", comment: ""),
action: #selector(quit), keyEquivalent: "q")
quit.target = self
menu.addItem(quit)
return menu
}
// MARK: - Actions
@objc private func showWindow() { showMainWindowHandler() }
@objc private func convertPreferred() { ConversionController.shared.trigger() }
@objc private func cleanClipboard() { PlainClipController.shared.trigger() }
@objc private func forceFullWidth() { ConversionController.shared.trigger(directionOverride: .toFullWidth, scopeOverride: nil) }
@objc private func forceHalfWidth() { ConversionController.shared.trigger(directionOverride: .toHalfWidth, scopeOverride: nil) }
@objc private func openAbout() { openAboutHandler() }
@objc private func quit() { NSApp.terminate(nil) }
@objc private func handleHotKeyChanged() { refresh() }
@objc private func handleMenuBarIconChanged() {
statusItem.isVisible = PreferencesStore.shared.showMenuBarIcon
}
}