Skip to content

Commit 93d7e52

Browse files
committed
Merge branch 'feature/status-bar-menu' into develop
2 parents e39fdc0 + b0d456a commit 93d7e52

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

XPCService/AppDelegate.swift

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,121 @@
11
import AppKit
22
import Service
3+
import ServiceManagement
34
import SwiftUI
45
import UserNotifications
6+
import XPCShared
57

68
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
79
let scheduledCleaner = ScheduledCleaner()
10+
private let userDefaultsObserver = UserDefaultsObserver()
11+
private var statusBarItem: NSStatusItem!
812

913
func applicationDidFinishLaunching(_: Notification) {
1014
NSApp.setActivationPolicy(.accessory)
15+
buildStatusBarMenu()
16+
AXIsProcessTrustedWithOptions(nil)
17+
}
18+
19+
@objc private func buildStatusBarMenu() {
20+
let statusBar = NSStatusBar.system
21+
statusBarItem = statusBar.statusItem(
22+
withLength: NSStatusItem.squareLength
23+
)
24+
statusBarItem.button?.image = NSImage(
25+
systemSymbolName: "steeringwheel",
26+
accessibilityDescription: nil
27+
)
28+
29+
let statusBarMenu = NSMenu(title: "Status Bar Menu")
30+
statusBarItem.menu = statusBarMenu
31+
32+
let copilotName = NSMenuItem(
33+
title: "Copilot for Xcode",
34+
action: nil,
35+
keyEquivalent: ""
36+
)
37+
38+
let toggleRealtimeSuggestions = NSMenuItem(
39+
title: "Real-time Suggestions",
40+
action: #selector(toggleRealtimeSuggestions),
41+
keyEquivalent: ""
42+
)
43+
toggleRealtimeSuggestions.state = UserDefaults.shared
44+
.bool(forKey: SettingsKey.realtimeSuggestionToggle) ? .on : .off
45+
toggleRealtimeSuggestions.target = self
46+
47+
let quitItem = NSMenuItem(
48+
title: "Quit",
49+
action: #selector(quit),
50+
keyEquivalent: ""
51+
)
52+
quitItem.target = self
53+
54+
statusBarMenu.addItem(copilotName)
55+
statusBarMenu.addItem(.separator())
56+
statusBarMenu.addItem(toggleRealtimeSuggestions)
57+
statusBarMenu.addItem(.separator())
58+
statusBarMenu.addItem(quitItem)
59+
60+
userDefaultsObserver.onChange = { key in
61+
switch key {
62+
case SettingsKey.realtimeSuggestionToggle:
63+
toggleRealtimeSuggestions.state = UserDefaults.shared
64+
.bool(forKey: SettingsKey.realtimeSuggestionToggle) ? .on : .off
65+
default:
66+
break
67+
}
68+
}
69+
UserDefaults.shared.addObserver(
70+
userDefaultsObserver,
71+
forKeyPath: SettingsKey.realtimeSuggestionToggle,
72+
options: .new,
73+
context: nil
74+
)
75+
}
76+
77+
@objc func quit() {
78+
exit(0)
79+
}
80+
81+
@objc func toggleRealtimeSuggestions() {
82+
let isOn = !UserDefaults.shared.bool(forKey: SettingsKey.realtimeSuggestionToggle)
83+
if isOn {
84+
if !AXIsProcessTrusted() {
85+
let alert = NSAlert()
86+
let image = NSImage(
87+
systemSymbolName: "exclamationmark.triangle.fill",
88+
accessibilityDescription: nil
89+
)
90+
var config = NSImage.SymbolConfiguration(
91+
textStyle: .body,
92+
scale: .large
93+
)
94+
config = config.applying(.init(hierarchicalColor: .systemYellow))
95+
alert.icon = image?.withSymbolConfiguration(config)
96+
alert.messageText = "Accessibility API Permission Required"
97+
alert.informativeText =
98+
"Permission not granted to use Accessibility API. Please turn in on in System Settings.app."
99+
alert.addButton(withTitle: "OK")
100+
alert.addButton(withTitle: "Cancel")
101+
alert.alertStyle = .warning
102+
alert.runModal()
103+
return
104+
}
105+
}
106+
UserDefaults.shared.set(isOn, forKey: SettingsKey.realtimeSuggestionToggle)
107+
}
108+
}
109+
110+
private class UserDefaultsObserver: NSObject {
111+
var onChange: ((String?) -> Void)?
112+
113+
override func observeValue(
114+
forKeyPath keyPath: String?,
115+
of object: Any?,
116+
change: [NSKeyValueChangeKey: Any]?,
117+
context: UnsafeMutableRawPointer?
118+
) {
119+
onChange?(keyPath)
11120
}
12121
}

0 commit comments

Comments
 (0)