@@ -11,7 +11,8 @@ let updateLocationIdentifier = "UpdateCheck"
1111@NSApplicationMain
1212class AppDelegate : NSObject , NSApplicationDelegate ,
1313 SPUStandardUserDriverDelegate ,
14- UNUserNotificationCenterDelegate
14+ UNUserNotificationCenterDelegate ,
15+ NSWindowDelegate
1516{
1617 var controller : Controller !
1718
@@ -40,20 +41,13 @@ class AppDelegate: NSObject, NSApplicationDelegate,
4041 )
4142
4243 func applicationDidFinishLaunching( _: Notification ) {
44+
4345 guard
4446 ProcessInfo . processInfo. environment [ " XCODE_RUNNING_FOR_PREVIEWS " ] != " 1 "
4547 else { return }
4648 guard !isRunningTests( ) else { return }
4749
4850 UNUserNotificationCenter . current ( ) . delegate = self
49- UNUserNotificationCenter . current ( ) . requestAuthorization ( options: [
50- . alert, . badge, . sound,
51- ] ) {
52- granted, error in
53- if let error = error {
54- print ( " Error requesting notification permission: \( error) " )
55- }
56- }
5751
5852 NSApp . mainMenu = MainMenu ( )
5953
@@ -75,8 +69,10 @@ class AppDelegate: NSObject, NSApplicationDelegate,
7569 }
7670
7771 statusItem. handlePreferences = {
78- self . settingsWindowController. show ( )
79- NSApp . activate ( ignoringOtherApps: true )
72+ self . showSettings ( )
73+ }
74+ statusItem. handleAbout = {
75+ NSApp . orderFrontStandardAboutPanel ( nil )
8076 }
8177 statusItem. handleReloadConfig = {
8278 self . config. reloadConfig ( )
@@ -98,6 +94,15 @@ class AppDelegate: NSObject, NSApplicationDelegate,
9894 }
9995 }
10096
97+ // Initialize status item according to current preference
98+ if Defaults [ . showMenuBarIcon] {
99+ statusItem. enable ( )
100+ } else {
101+ statusItem. disable ( )
102+ }
103+
104+ // Activation policy is managed solely by the Settings window
105+
101106 registerGlobalShortcuts ( )
102107 }
103108
@@ -143,8 +148,7 @@ class AppDelegate: NSObject, NSApplicationDelegate,
143148
144149 @IBAction
145150 func settingsMenuItemActionHandler( _: NSMenuItem ) {
146- settingsWindowController. show ( )
147- NSApp . activate ( ignoringOtherApps: true )
151+ showSettings ( )
148152 }
149153
150154 func show( ) {
@@ -165,19 +169,22 @@ class AppDelegate: NSObject, NSApplicationDelegate,
165169 _ handleShowingUpdate: Bool , forUpdate update: SUAppcastItem ,
166170 state: SPUUserUpdateState
167171 ) {
168- NSApp . setActivationPolicy ( . regular )
172+ // Do not change activation policy here; Settings drives visibility
169173
170174 if !state. userInitiated {
171175 NSApp . dockTile. badgeLabel = " 1 "
172176
173- let content = UNMutableNotificationContent ( )
174- content. title = " Leader Key Update Available "
175- content. body = " Version \( update. displayVersionString) is now available "
177+ requestNotificationsAuthorizationIfNeeded { granted in
178+ guard granted else { return }
179+ let content = UNMutableNotificationContent ( )
180+ content. title = " Leader Key Update Available "
181+ content. body = " Version \( update. displayVersionString) is now available "
176182
177- let request = UNNotificationRequest (
178- identifier: updateLocationIdentifier, content: content,
179- trigger: nil )
180- UNUserNotificationCenter . current ( ) . add ( request)
183+ let request = UNNotificationRequest (
184+ identifier: updateLocationIdentifier, content: content,
185+ trigger: nil )
186+ UNUserNotificationCenter . current ( ) . add ( request)
187+ }
181188 }
182189 }
183190
@@ -192,9 +199,7 @@ class AppDelegate: NSObject, NSApplicationDelegate,
192199 ] )
193200 }
194201
195- func standardUserDriverWillFinishUpdateSession( ) {
196- NSApp . setActivationPolicy ( . accessory)
197- }
202+ func standardUserDriverWillFinishUpdateSession( ) { }
198203
199204 // MARK: - UNUserNotificationCenter Delegate
200205
@@ -229,6 +234,15 @@ class AppDelegate: NSObject, NSApplicationDelegate,
229234 private func handleURL( _ url: URL ) {
230235 guard url. scheme == " leaderkey " else { return }
231236
237+ if url. host == " settings " {
238+ showSettings ( )
239+ return
240+ }
241+ if url. host == " about " {
242+ NSApp . orderFrontStandardAboutPanel ( nil )
243+ return
244+ }
245+
232246 show ( )
233247
234248 if url. host == " navigate " ,
@@ -258,4 +272,43 @@ class AppDelegate: NSObject, NSApplicationDelegate,
258272 }
259273 }
260274 }
275+
276+ // MARK: - Activation Policy: Only Settings Visibility Controls It
277+
278+ private func showSettings( ) {
279+ // Behave like a normal app while Settings is open
280+ NSApp . setActivationPolicy ( . regular)
281+ settingsWindowController. show ( )
282+ NSApp . activate ( ignoringOtherApps: true )
283+ settingsWindowController. window? . delegate = self
284+ }
285+
286+ // Revert to accessory when Settings window closes
287+ func windowWillClose( _ notification: Notification ) {
288+ guard let win = notification. object as? NSWindow ,
289+ win == settingsWindowController. window
290+ else { return }
291+ NSApp . setActivationPolicy ( . accessory)
292+ }
293+
294+ private func requestNotificationsAuthorizationIfNeeded(
295+ completion: @escaping ( Bool ) -> Void
296+ ) {
297+ UNUserNotificationCenter . current ( ) . getNotificationSettings { settings in
298+ switch settings. authorizationStatus {
299+ case . notDetermined:
300+ UNUserNotificationCenter . current ( ) . requestAuthorization ( options: [
301+ . alert, . badge, . sound,
302+ ] ) { granted, _ in
303+ DispatchQueue . main. async { completion ( granted) }
304+ }
305+ case . authorized, . provisional, . ephemeral:
306+ DispatchQueue . main. async { completion ( true ) }
307+ case . denied:
308+ DispatchQueue . main. async { completion ( false ) }
309+ @unknown default :
310+ DispatchQueue . main. async { completion ( false ) }
311+ }
312+ }
313+ }
261314}
0 commit comments