From b9c9ea7d5b5ddb2f3f822c5fc01e593230aefe57 Mon Sep 17 00:00:00 2001 From: Alan Hamlett Date: Thu, 10 Aug 2023 23:53:16 +0200 Subject: [PATCH] Show indicator when a11y permission disabled --- WakaTime/AppDelegate.swift | 31 +++++++++++++++--- WakaTime/Helpers/Accessibility.swift | 6 ++-- .../WakaTimeDisabled.imageset/32.png | Bin 0 -> 1092 bytes .../WakaTimeDisabled.imageset/64.png | Bin 0 -> 1171 bytes .../WakaTimeDisabled.imageset/Contents.json | 25 ++++++++++++++ WakaTime/WakaTime.swift | 14 ++++++-- WakaTime/Watcher.swift | 3 ++ 7 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 WakaTime/Resources/Assets.xcassets/WakaTimeDisabled.imageset/32.png create mode 100644 WakaTime/Resources/Assets.xcassets/WakaTimeDisabled.imageset/64.png create mode 100644 WakaTime/Resources/Assets.xcassets/WakaTimeDisabled.imageset/Contents.json diff --git a/WakaTime/AppDelegate.swift b/WakaTime/AppDelegate.swift index 9e3ccad..4aa3757 100644 --- a/WakaTime/AppDelegate.swift +++ b/WakaTime/AppDelegate.swift @@ -2,9 +2,11 @@ import AppUpdater import Cocoa import UserNotifications -class AppDelegate: NSObject, NSApplicationDelegate { +class AppDelegate: NSObject, NSApplicationDelegate, StatusBarDelegate { var window: NSWindow! var statusBarItem: NSStatusItem! + var statusBarA11yItem: NSMenuItem! + var statusBarA11yStatus: Bool = true var settingsWindowController = SettingsWindowController() var monitoredAppsWindowController = MonitoredAppsWindowController() var wakaTime: WakaTime? @@ -12,9 +14,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { let updater = AppUpdater(owner: "wakatime", repo: "macos-wakatime") func applicationDidFinishLaunching(_ aNotification: Notification) { - - wakaTime = WakaTime() - // Handle deep links let eventManager = NSAppleEventManager.shared() eventManager.setEventHandler( @@ -29,6 +28,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { let menu = NSMenu() + statusBarA11yItem = NSMenuItem( + title: "* A11y permission needed *", + action: #selector(AppDelegate.a11yClicked(_:)), + keyEquivalent: "") + statusBarA11yItem.isHidden = true + menu.addItem(statusBarA11yItem) menu.addItem(withTitle: "Dashboard", action: #selector(AppDelegate.dashboardClicked(_:)), keyEquivalent: "") menu.addItem(withTitle: "Settings", action: #selector(AppDelegate.settingsClicked(_:)), keyEquivalent: "") menu.addItem(withTitle: "Monitored Apps", action: #selector(AppDelegate.monitoredAppsClicked(_:)), keyEquivalent: "") @@ -38,6 +43,8 @@ class AppDelegate: NSObject, NSApplicationDelegate { menu.addItem(withTitle: "Quit", action: #selector(AppDelegate.quitClicked(_:)), keyEquivalent: "") statusBarItem.menu = menu + + wakaTime = WakaTime(self) } @objc func handleGetURL(_ event: NSAppleEventDescriptor, withReplyEvent replyEvent: NSAppleEventDescriptor) { @@ -93,10 +100,26 @@ class AppDelegate: NSObject, NSApplicationDelegate { } } + @objc func a11yClicked(_ sender: AnyObject) { + a11yStatusChanged(Accessibility.requestA11yPermission()) + } + @objc func quitClicked(_ sender: AnyObject) { NSApplication.shared.terminate(self) } + func a11yStatusChanged(_ hasPermission: Bool) { + guard statusBarA11yStatus != hasPermission else { return } + + statusBarA11yStatus = hasPermission + if hasPermission { + statusBarItem.button?.image = NSImage(named: NSImage.Name("WakaTime")) + } else { + statusBarItem.button?.image = NSImage(named: NSImage.Name("WakaTimeDisabled")) + } + statusBarA11yItem.isHidden = hasPermission + } + private func showSettings() { NSApp.activate(ignoringOtherApps: true) settingsWindowController.showWindow(self) diff --git a/WakaTime/Helpers/Accessibility.swift b/WakaTime/Helpers/Accessibility.swift index bae9ea5..ddf9c5b 100644 --- a/WakaTime/Helpers/Accessibility.swift +++ b/WakaTime/Helpers/Accessibility.swift @@ -1,12 +1,10 @@ import AppKit class Accessibility { - public static func requestA11yPermission() { + public static func requestA11yPermission() -> Bool { let prompt = kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String let options: NSDictionary = [prompt: true] let appHasPermission = AXIsProcessTrustedWithOptions(options) - if appHasPermission { - // print("has a11y permission") - } + return appHasPermission } } diff --git a/WakaTime/Resources/Assets.xcassets/WakaTimeDisabled.imageset/32.png b/WakaTime/Resources/Assets.xcassets/WakaTimeDisabled.imageset/32.png new file mode 100644 index 0000000000000000000000000000000000000000..f26081dbd126c6b0e01107caf30e5bbbcdc5d30b GIT binary patch literal 1092 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0U@Qsn32_B-;ozsLBAg9m{8m%@ zrKa>#O$j2%h%AS}=7ov;R8{(*q5$OWkrfkQU^uR&^;b>lo2ueJb>#>SHaAw5ud0fl zRTSTY)rd1NJXMlECL;+{e_dV%NWM{#2a?OhMRIt!eb`vHN{ZPqGpjH%UX_>eV`KdS zcHvJoMF(bPpu$)|E~03H888RSSHh-PC8WnkDWB?V*yE&Z>d@?TvU=-=OJN4a zGAc7N-c^)6CL^&)LiC}cEYL^w*?$Xx8gfg5{DK*NvWowGJ?n`!@9z(%GCp59&>nMS z)e^19e_mYQE0m--*#7?g{rmU#hZi=@nj9J!U}Ylx@89pAKYxDw`2O9SSI-|mym$B3 z&8z3noH}*v@PQ30mM>X2f7Z;YlPC7}wA5FY=VzxR#>PfRhd9|7Ye|Td9Qk{Xfq_ZL z)5S5w;&f_oYV&Oao~_dAFE>rOt$o<=e%=`%=-G7FV~T;X{Q*MWQ)fW(CXioHor2jvu!O_{b7?^8dxvUaArf)_VCxw6BEw`erIE3=F;*|c0K>*lW>&9 zFY9bUR}G=FOBa?ue6;7=mZ-%2o=+lXAIx}@^751F)=eLsR^&g`+h%FG;{5fxeg5~a zuliQ>xM^3BxYvZU%G|sAH}9}` zb@$2U{~?vGtX5h5`oBUv=KnJOSLju6>AS}My~RH!C=_3r{BeExod3axKBqmm)!mvm zIn(xErT2yn#?ODt-i*9uzv0!dBj4kT&mK)q&$s(`>xQ|>H~DRA`cr?OG_?RFYEM@` Jmvv4FO#m!mv(o?o literal 0 HcmV?d00001 diff --git a/WakaTime/Resources/Assets.xcassets/WakaTimeDisabled.imageset/64.png b/WakaTime/Resources/Assets.xcassets/WakaTimeDisabled.imageset/64.png new file mode 100644 index 0000000000000000000000000000000000000000..ccf7e5cc5c3868a248d28de167a766a39d39c57e GIT binary patch literal 1171 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!J_q=OxB_W7U}9kSp{4}n0vSL6 z(o8Yzoj61UQXtitkha5@lqiH zM=maP28KsU@&Zgu791QOR24s{D4da(nIRzp)b&6~?wY);3@dA$px_co@u^}Wl|lk> z0=z!F97gQyKm|Y5l)kDd0mYSBS+WH9WLQ`>OG}gq3dHg8T5)jjF)^_-G8PB7Dg%|e zlmz(&GrakEh4)XdOsnXZdSmN{Nx`R!*p@CxIDcf#tP17b8?}GtM*IF+Jj4FQ-P>mm zZk?TIDDdyw*S9a9KfZbS^x`QK>x=wtRE(dU-o?Pc%%SBqr%KZ#Ac zD5psz?3S4HtSy?`vgQ0Iq$NJ8Jt~Q zp_9cwnaTQ-fo!ko7IxtSEz+DhQ3YFgC+*O!v*+7BnVIi#tJJrYIcdq))Q!IR{X6A% zV*ch$X$vpTomhWqg=37*Hz}JfGmock*}r&umFL!UVSTUox=G@EhrLv8nx-Um1|Q%I zv%0A&a`<0HgeSjrs6&2-Y0K3^i5WEkOXT{Ud&6_f=l1bAGTXT;?PAJ4GjRf6)Q1xm z8VPH^2%J1`$~}cS;-KpUUl)m`A6|LwT`ru=)_KJ6gh;LX1C1wA67KU0jPA^KC=NO@ z_xpC60}5(oEps9)XH9$4@hALK1Oe;4_-_n z6FxgGHvG8euj7Xw|NNDAzfH5c`X=uXySc+9gWcAfjUO?}v~=zWvs*Rmjq|D>43bSY zCKI{#iY#+~%C@qT$5AI~pJsS3`+s?+`Tj-DmTgALizKJSSVePrZCz6q z^!E5o39hXdlr)m{G`3ADi?inFeARonHsgwO|ALtuT6L~pxulMEaNc6o-|HUPKatD% zt6%OVjz4;0DM?JW%7 Void +} diff --git a/WakaTime/Watcher.swift b/WakaTime/Watcher.swift index c0ce747..78aff59 100644 --- a/WakaTime/Watcher.swift +++ b/WakaTime/Watcher.swift @@ -8,6 +8,7 @@ class Watcher: NSObject { var appVersions: [String: String] = [:] var eventHandler: ((_ app: NSRunningApplication, _ path: URL, _ isWrite: Bool, _ isBuilding: Bool) -> Void)? + var statusBarDelegate: StatusBarDelegate? var isBuilding = false var activeApp: NSRunningApplication? private var observer: AXObserver? @@ -117,8 +118,10 @@ class Watcher: NSObject { observeActivityText(activeWindow: activeWindow) } // NSLog("Watching for file changes on \(app.localizedName ?? "nil")") + self.statusBarDelegate?.a11yStatusChanged(true) } catch { NSLog("Failed to setup AXObserver: \(error.localizedDescription)") + self.statusBarDelegate?.a11yStatusChanged(false) } }