diff --git a/Scripts/create_app_bundle.sh b/Scripts/create_app_bundle.sh index 9b03dba..fe832df 100755 --- a/Scripts/create_app_bundle.sh +++ b/Scripts/create_app_bundle.sh @@ -65,6 +65,8 @@ cat > "$CONTENTS_DIR/Info.plist" <public.app-category.utilities NSHighResolutionCapable + NSAppleEventsUsageDescription + Firelink needs permission to control Finder so it can sleep, restart, or shut down your Mac after scheduled downloads finish. PLIST diff --git a/Sources/Firelink/SchedulerController.swift b/Sources/Firelink/SchedulerController.swift index 2c09a69..52a332e 100644 --- a/Sources/Firelink/SchedulerController.swift +++ b/Sources/Firelink/SchedulerController.swift @@ -200,7 +200,36 @@ final class SchedulerController: ObservableObject { func requestAutomationPermission() { let target = NSAppleEventDescriptor(bundleIdentifier: "com.apple.finder") - _ = AEDeterminePermissionToAutomateTarget(target.aeDesc, typeWildCard, typeWildCard, true) + let status = AEDeterminePermissionToAutomateTarget(target.aeDesc, typeWildCard, typeWildCard, true) + + if status != noErr { + triggerAutomationConsentPrompt() + } + checkAutomationPermission() + + if !hasAutomationPermission { + openAutomationPermissionSettings() + } + } + + func openAutomationPermissionSettings() { + guard let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation") else { + return + } + + NSWorkspace.shared.open(url) + } + + private func triggerAutomationConsentPrompt() { + let scriptCode = "tell application \"Finder\" to get name" + + var error: NSDictionary? + if let script = NSAppleScript(source: scriptCode) { + script.executeAndReturnError(&error) + if let error { + print("Failed to trigger Automation permission prompt: \(error)") + } + } } } diff --git a/Sources/Firelink/SchedulerView.swift b/Sources/Firelink/SchedulerView.swift index fbb47d3..941b8ed 100644 --- a/Sources/Firelink/SchedulerView.swift +++ b/Sources/Firelink/SchedulerView.swift @@ -20,9 +20,13 @@ struct SchedulerView: View { ScrollView { VStack(alignment: .leading, spacing: 24) { - timeSelectionSection - queueSelectionSection - postActionSection + VStack(alignment: .leading, spacing: 24) { + timeSelectionSection + queueSelectionSection + postActionSection + } + .opacity(isEnabled ? 1.0 : 0.5) + .disabled(!isEnabled) Divider() permissionsSection @@ -30,8 +34,6 @@ struct SchedulerView: View { .padding(24) } .frame(maxWidth: .infinity, alignment: .leading) - .opacity(isEnabled ? 1.0 : 0.5) - .disabled(!isEnabled) } .onAppear { loadState() @@ -153,16 +155,14 @@ struct SchedulerView: View { Text("System Permissions") .font(.headline) - Text("Firelink needs permission to control System Events in order to automatically sleep, restart, or shut down your Mac after downloads finish.") + Text("Firelink needs Automation permission to control Finder in order to automatically sleep, restart, or shut down your Mac after downloads finish.") .font(.subheadline) .foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) if schedulerController.hasAutomationPermission { - Button("Revoke Permission") { - if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation") { - NSWorkspace.shared.open(url) - } + Button("Revoke Permissions") { + schedulerController.openAutomationPermissionSettings() } .buttonStyle(.bordered) } else {