From aa8bfad20e2d9192d8e281d0c1808fbea3c2850c Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 28 Oct 2024 19:08:16 +0100 Subject: [PATCH 1/6] Handle ignore unignore URL actions --- Rectangle/ApplicationToggle.swift | 30 ++++ Rectangle/Base.lproj/Main.storyboard | 196 +++++++++++++-------------- Rectangle/WindowAction.swift | 14 +- 3 files changed, 139 insertions(+), 101 deletions(-) diff --git a/Rectangle/ApplicationToggle.swift b/Rectangle/ApplicationToggle.swift index 12db1f5b..6bf64fc8 100644 --- a/Rectangle/ApplicationToggle.swift +++ b/Rectangle/ApplicationToggle.swift @@ -21,12 +21,14 @@ class ApplicationToggle: NSObject { self.shortcutManager = shortcutManager super.init() registerFrontAppChangeNote() + subscribe() if let disabledApps = getDisabledApps() { self.disabledApps = disabledApps } } public func reloadFromDefaults() { + subscribe() if let disabledApps = getDisabledApps() { self.disabledApps = disabledApps } else { @@ -34,6 +36,10 @@ class ApplicationToggle: NSObject { } } + deinit { + unsubscribe() + } + private func saveDisabledApps() { let encoder = JSONEncoder() if let jsonDisabledApps = try? encoder.encode(disabledApps) { @@ -119,6 +125,30 @@ class ApplicationToggle: NSObject { } } + @objc func windowActionTriggered(notification: NSNotification) { + guard let parameters = notification.object as? ExecutionParameters else { return } + + let action = parameters.action + + switch action { + case .ignoreApp: + disableFrontApp() + return + case .unignoreApp: + enableFrontApp() + return + default: break // NOOP + } + } + + private func unsubscribe() { + NotificationCenter.default.removeObserver(self) + } + + private func subscribe() { + NotificationCenter.default.addObserver(self, selector: #selector(windowActionTriggered), name: WindowAction.ignoreApp.notificationName, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(windowActionTriggered), name: WindowAction.unignoreApp.notificationName, object: nil) + } } // todo mode diff --git a/Rectangle/Base.lproj/Main.storyboard b/Rectangle/Base.lproj/Main.storyboard index a3b61729..28253a2a 100644 --- a/Rectangle/Base.lproj/Main.storyboard +++ b/Rectangle/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -337,7 +337,7 @@ - + @@ -386,7 +386,7 @@ - + @@ -435,7 +435,7 @@ - + @@ -484,7 +484,7 @@ - + @@ -536,7 +536,7 @@ - + @@ -595,7 +595,7 @@ - + @@ -647,7 +647,7 @@ - + @@ -699,7 +699,7 @@ - + @@ -751,7 +751,7 @@ - + @@ -832,7 +832,7 @@ - + @@ -881,7 +881,7 @@ - + @@ -930,7 +930,7 @@ - + @@ -979,7 +979,7 @@ - + @@ -1028,7 +1028,7 @@ - + @@ -1077,7 +1077,7 @@ - + @@ -1126,7 +1126,7 @@ - + @@ -1182,7 +1182,7 @@ - + @@ -1231,7 +1231,7 @@ - + @@ -1311,10 +1311,10 @@ - + - + @@ -1351,7 +1351,7 @@ - + @@ -1400,7 +1400,7 @@ - + @@ -1449,7 +1449,7 @@ - + @@ -1498,7 +1498,7 @@ - + @@ -1547,7 +1547,7 @@ - + @@ -1603,7 +1603,7 @@ - + @@ -1652,7 +1652,7 @@ - + @@ -1701,7 +1701,7 @@ - + @@ -1750,7 +1750,7 @@ - + @@ -1799,7 +1799,7 @@ - + @@ -1848,7 +1848,7 @@ - + @@ -1930,7 +1930,7 @@ - + @@ -1979,7 +1979,7 @@ - + @@ -2028,7 +2028,7 @@ - + @@ -2077,7 +2077,7 @@ - + @@ -2133,7 +2133,7 @@ - + @@ -2182,7 +2182,7 @@ - + @@ -2231,7 +2231,7 @@ - + @@ -2280,7 +2280,7 @@ - + @@ -2329,7 +2329,7 @@ - + @@ -2378,7 +2378,7 @@ - + @@ -2588,7 +2588,7 @@ - + @@ -2622,7 +2622,7 @@ - + @@ -2672,7 +2672,7 @@ - + @@ -2729,7 +2729,7 @@ - + @@ -2744,7 +2744,7 @@ - + @@ -2814,7 +2814,7 @@ - + @@ -2841,7 +2841,7 @@ - + @@ -2855,7 +2855,7 @@ - + @@ -2863,7 +2863,7 @@ - + @@ -2876,7 +2876,7 @@ - + @@ -2887,7 +2887,7 @@ - + @@ -2899,7 +2899,7 @@ - + @@ -2938,7 +2938,7 @@ - + @@ -2974,7 +2974,7 @@ - + @@ -3038,7 +3038,7 @@ - + @@ -3053,7 +3053,7 @@ - + @@ -3073,7 +3073,7 @@ - + @@ -3113,10 +3113,10 @@ - + - + @@ -3328,7 +3328,7 @@ DQ - + @@ -3389,7 +3389,7 @@ DQ - + @@ -3405,7 +3405,7 @@ DQ - + @@ -3416,7 +3416,7 @@ DQ - + @@ -3424,7 +3424,7 @@ DQ - + @@ -3434,7 +3434,7 @@ DQ - + @@ -3454,7 +3454,7 @@ DQ - + @@ -3551,7 +3551,7 @@ DQ - + @@ -3559,7 +3559,7 @@ DQ - + @@ -3607,7 +3607,7 @@ DQ - + @@ -3615,7 +3615,7 @@ DQ - + @@ -3762,7 +3762,7 @@ DQ - + @@ -3780,7 +3780,7 @@ DQ - + @@ -3798,7 +3798,7 @@ DQ - + @@ -3831,7 +3831,7 @@ DQ - + @@ -3857,7 +3857,7 @@ DQ - + @@ -3890,7 +3890,7 @@ DQ - + @@ -3908,7 +3908,7 @@ DQ - + @@ -3926,7 +3926,7 @@ DQ - + @@ -3984,7 +3984,7 @@ DQ - + @@ -4002,7 +4002,7 @@ DQ - + @@ -4020,7 +4020,7 @@ DQ - + @@ -4053,7 +4053,7 @@ DQ - + @@ -4079,7 +4079,7 @@ DQ - + @@ -4112,7 +4112,7 @@ DQ - + @@ -4130,7 +4130,7 @@ DQ - + @@ -4148,7 +4148,7 @@ DQ - + @@ -4279,7 +4279,7 @@ DQ - + @@ -4298,7 +4298,7 @@ DQ - + diff --git a/Rectangle/WindowAction.swift b/Rectangle/WindowAction.swift index 19fee3c8..928d07c0 100644 --- a/Rectangle/WindowAction.swift +++ b/Rectangle/WindowAction.swift @@ -92,7 +92,9 @@ enum WindowAction: Int, Codable { halveHeightUp = 76, halveHeightDown = 77, halveWidthLeft = 78, - halveWidthRight = 79 + halveWidthRight = 79, + ignoreApp = 80, + unignoreApp = 81 // Order matters here - it's used in the menu static let active = [leftHalf, rightHalf, centerHalf, topHalf, bottomHalf, @@ -114,7 +116,8 @@ enum WindowAction: Int, Codable { halveHeightUp, halveHeightDown, halveWidthLeft, halveWidthRight, tileAll, cascadeAll, leftTodo, rightTodo, - cascadeActiveApp + cascadeActiveApp, + ignoreApp, unignoreApp ] func post() { @@ -225,6 +228,8 @@ enum WindowAction: Int, Codable { case .rightTodo: return "rightTodo" case .cascadeActiveApp: return "cascadeActiveApp" case .centerProminently: return "centerProminently" + case .ignoreApp: return "ignoreApp" + case .unignoreApp: return "unignoreApp" } } @@ -363,6 +368,8 @@ enum WindowAction: Int, Codable { return nil case .centerProminently: return nil + case .ignoreApp, .unignoreApp: + return nil } return NSLocalizedString(key, tableName: "Main", value: value, comment: "") @@ -537,6 +544,7 @@ enum WindowAction: Int, Codable { case .rightTodo: return NSImage() case .cascadeActiveApp: return NSImage() case .centerProminently: return NSImage() + case .ignoreApp, .unignoreApp: return NSImage() } } @@ -579,7 +587,7 @@ enum WindowAction: Int, Codable { return Defaults.applyGapsToMaximize.userDisabled ? .none : .both; case .maximizeHeight: return Defaults.applyGapsToMaximizeHeight.userDisabled ? .none : .vertical; - case .almostMaximize, .previousDisplay, .nextDisplay, .larger, .smaller, .center, .centerProminently, .restore, .specified, .reverseAll, .tileAll, .cascadeAll, .cascadeActiveApp: + case .almostMaximize, .previousDisplay, .nextDisplay, .larger, .smaller, .center, .centerProminently, .restore, .specified, .reverseAll, .tileAll, .cascadeAll, .cascadeActiveApp, .ignoreApp, .unignoreApp: return .none } } From 31145b526568a37af1ad45b5f4f771451283bc9b Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 30 Oct 2024 13:03:13 +0100 Subject: [PATCH 2/6] Handle ignore unignore URL actions via AppDelegate --- Rectangle/AppDelegate.swift | 21 +++++++++++++++------ Rectangle/ApplicationToggle.swift | 31 ------------------------------- Rectangle/WindowAction.swift | 14 +++----------- 3 files changed, 18 insertions(+), 48 deletions(-) diff --git a/Rectangle/AppDelegate.swift b/Rectangle/AppDelegate.swift index 7d341694..70eece45 100644 --- a/Rectangle/AppDelegate.swift +++ b/Rectangle/AppDelegate.swift @@ -556,16 +556,25 @@ extension AppDelegate { return name.map { $0.isUppercase ? "-" + $0.lowercased() : String($0) }.joined() } for url in urls { - guard + guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true), - components.host == "execute-action", - components.path.isEmpty, - let name = (components.queryItems?.first { $0.name == "name" })?.value, - let action = (WindowAction.active.first { getUrlName($0.name) == name }) + components.path.isEmpty else { continue } - action.postUrl() + + let name = (components.queryItems?.first { $0.name == "name" })?.value + switch (components.host, name) { + case ("execute-action", _): + let action = (WindowAction.active.first { getUrlName($0.name) == name }) + action?.postUrl() + case ("execute-task", "ignore-app"): + self.applicationToggle.disableFrontApp() + case ("execute-task", "unignore-app"): + self.applicationToggle.enableFrontApp() + default: + continue + } } } } diff --git a/Rectangle/ApplicationToggle.swift b/Rectangle/ApplicationToggle.swift index 6bf64fc8..f442760d 100644 --- a/Rectangle/ApplicationToggle.swift +++ b/Rectangle/ApplicationToggle.swift @@ -21,14 +21,12 @@ class ApplicationToggle: NSObject { self.shortcutManager = shortcutManager super.init() registerFrontAppChangeNote() - subscribe() if let disabledApps = getDisabledApps() { self.disabledApps = disabledApps } } public func reloadFromDefaults() { - subscribe() if let disabledApps = getDisabledApps() { self.disabledApps = disabledApps } else { @@ -36,10 +34,6 @@ class ApplicationToggle: NSObject { } } - deinit { - unsubscribe() - } - private func saveDisabledApps() { let encoder = JSONEncoder() if let jsonDisabledApps = try? encoder.encode(disabledApps) { @@ -124,31 +118,6 @@ class ApplicationToggle: NSObject { } } } - - @objc func windowActionTriggered(notification: NSNotification) { - guard let parameters = notification.object as? ExecutionParameters else { return } - - let action = parameters.action - - switch action { - case .ignoreApp: - disableFrontApp() - return - case .unignoreApp: - enableFrontApp() - return - default: break // NOOP - } - } - - private func unsubscribe() { - NotificationCenter.default.removeObserver(self) - } - - private func subscribe() { - NotificationCenter.default.addObserver(self, selector: #selector(windowActionTriggered), name: WindowAction.ignoreApp.notificationName, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(windowActionTriggered), name: WindowAction.unignoreApp.notificationName, object: nil) - } } // todo mode diff --git a/Rectangle/WindowAction.swift b/Rectangle/WindowAction.swift index 928d07c0..19fee3c8 100644 --- a/Rectangle/WindowAction.swift +++ b/Rectangle/WindowAction.swift @@ -92,9 +92,7 @@ enum WindowAction: Int, Codable { halveHeightUp = 76, halveHeightDown = 77, halveWidthLeft = 78, - halveWidthRight = 79, - ignoreApp = 80, - unignoreApp = 81 + halveWidthRight = 79 // Order matters here - it's used in the menu static let active = [leftHalf, rightHalf, centerHalf, topHalf, bottomHalf, @@ -116,8 +114,7 @@ enum WindowAction: Int, Codable { halveHeightUp, halveHeightDown, halveWidthLeft, halveWidthRight, tileAll, cascadeAll, leftTodo, rightTodo, - cascadeActiveApp, - ignoreApp, unignoreApp + cascadeActiveApp ] func post() { @@ -228,8 +225,6 @@ enum WindowAction: Int, Codable { case .rightTodo: return "rightTodo" case .cascadeActiveApp: return "cascadeActiveApp" case .centerProminently: return "centerProminently" - case .ignoreApp: return "ignoreApp" - case .unignoreApp: return "unignoreApp" } } @@ -368,8 +363,6 @@ enum WindowAction: Int, Codable { return nil case .centerProminently: return nil - case .ignoreApp, .unignoreApp: - return nil } return NSLocalizedString(key, tableName: "Main", value: value, comment: "") @@ -544,7 +537,6 @@ enum WindowAction: Int, Codable { case .rightTodo: return NSImage() case .cascadeActiveApp: return NSImage() case .centerProminently: return NSImage() - case .ignoreApp, .unignoreApp: return NSImage() } } @@ -587,7 +579,7 @@ enum WindowAction: Int, Codable { return Defaults.applyGapsToMaximize.userDisabled ? .none : .both; case .maximizeHeight: return Defaults.applyGapsToMaximizeHeight.userDisabled ? .none : .vertical; - case .almostMaximize, .previousDisplay, .nextDisplay, .larger, .smaller, .center, .centerProminently, .restore, .specified, .reverseAll, .tileAll, .cascadeAll, .cascadeActiveApp, .ignoreApp, .unignoreApp: + case .almostMaximize, .previousDisplay, .nextDisplay, .larger, .smaller, .center, .centerProminently, .restore, .specified, .reverseAll, .tileAll, .cascadeAll, .cascadeActiveApp: return .none } } From daba94da0709666df2f04574cbbb6ecadad8b40e Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 30 Oct 2024 13:05:09 +0100 Subject: [PATCH 3/6] Restore sotryboard from main --- Rectangle/Base.lproj/Main.storyboard | 196 +++++++++++++-------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/Rectangle/Base.lproj/Main.storyboard b/Rectangle/Base.lproj/Main.storyboard index 28253a2a..a3b61729 100644 --- a/Rectangle/Base.lproj/Main.storyboard +++ b/Rectangle/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -337,7 +337,7 @@ - + @@ -386,7 +386,7 @@ - + @@ -435,7 +435,7 @@ - + @@ -484,7 +484,7 @@ - + @@ -536,7 +536,7 @@ - + @@ -595,7 +595,7 @@ - + @@ -647,7 +647,7 @@ - + @@ -699,7 +699,7 @@ - + @@ -751,7 +751,7 @@ - + @@ -832,7 +832,7 @@ - + @@ -881,7 +881,7 @@ - + @@ -930,7 +930,7 @@ - + @@ -979,7 +979,7 @@ - + @@ -1028,7 +1028,7 @@ - + @@ -1077,7 +1077,7 @@ - + @@ -1126,7 +1126,7 @@ - + @@ -1182,7 +1182,7 @@ - + @@ -1231,7 +1231,7 @@ - + @@ -1311,10 +1311,10 @@ - + - + @@ -1351,7 +1351,7 @@ - + @@ -1400,7 +1400,7 @@ - + @@ -1449,7 +1449,7 @@ - + @@ -1498,7 +1498,7 @@ - + @@ -1547,7 +1547,7 @@ - + @@ -1603,7 +1603,7 @@ - + @@ -1652,7 +1652,7 @@ - + @@ -1701,7 +1701,7 @@ - + @@ -1750,7 +1750,7 @@ - + @@ -1799,7 +1799,7 @@ - + @@ -1848,7 +1848,7 @@ - + @@ -1930,7 +1930,7 @@ - + @@ -1979,7 +1979,7 @@ - + @@ -2028,7 +2028,7 @@ - + @@ -2077,7 +2077,7 @@ - + @@ -2133,7 +2133,7 @@ - + @@ -2182,7 +2182,7 @@ - + @@ -2231,7 +2231,7 @@ - + @@ -2280,7 +2280,7 @@ - + @@ -2329,7 +2329,7 @@ - + @@ -2378,7 +2378,7 @@ - + @@ -2588,7 +2588,7 @@ - + @@ -2622,7 +2622,7 @@ - + @@ -2672,7 +2672,7 @@ - + @@ -2729,7 +2729,7 @@ - + @@ -2744,7 +2744,7 @@ - + @@ -2814,7 +2814,7 @@ - + @@ -2841,7 +2841,7 @@ - + @@ -2855,7 +2855,7 @@ - + @@ -2863,7 +2863,7 @@ - + @@ -2876,7 +2876,7 @@ - + @@ -2887,7 +2887,7 @@ - + @@ -2899,7 +2899,7 @@ - + @@ -2938,7 +2938,7 @@ - + @@ -2974,7 +2974,7 @@ - + @@ -3038,7 +3038,7 @@ - + @@ -3053,7 +3053,7 @@ - + @@ -3073,7 +3073,7 @@ - + @@ -3113,10 +3113,10 @@ - + - + @@ -3328,7 +3328,7 @@ DQ - + @@ -3389,7 +3389,7 @@ DQ - + @@ -3405,7 +3405,7 @@ DQ - + @@ -3416,7 +3416,7 @@ DQ - + @@ -3424,7 +3424,7 @@ DQ - + @@ -3434,7 +3434,7 @@ DQ - + @@ -3454,7 +3454,7 @@ DQ - + @@ -3551,7 +3551,7 @@ DQ - + @@ -3559,7 +3559,7 @@ DQ - + @@ -3607,7 +3607,7 @@ DQ - + @@ -3615,7 +3615,7 @@ DQ - + @@ -3762,7 +3762,7 @@ DQ - + @@ -3780,7 +3780,7 @@ DQ - + @@ -3798,7 +3798,7 @@ DQ - + @@ -3831,7 +3831,7 @@ DQ - + @@ -3857,7 +3857,7 @@ DQ - + @@ -3890,7 +3890,7 @@ DQ - + @@ -3908,7 +3908,7 @@ DQ - + @@ -3926,7 +3926,7 @@ DQ - + @@ -3984,7 +3984,7 @@ DQ - + @@ -4002,7 +4002,7 @@ DQ - + @@ -4020,7 +4020,7 @@ DQ - + @@ -4053,7 +4053,7 @@ DQ - + @@ -4079,7 +4079,7 @@ DQ - + @@ -4112,7 +4112,7 @@ DQ - + @@ -4130,7 +4130,7 @@ DQ - + @@ -4148,7 +4148,7 @@ DQ - + @@ -4279,7 +4279,7 @@ DQ - + @@ -4298,7 +4298,7 @@ DQ - + From f905c59080fe57177e9720719550a5e063c3c738 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 31 Oct 2024 00:43:22 +0100 Subject: [PATCH 4/6] Add support for app-bundle-id to ignore/unignore url tasks --- Rectangle/AppDelegate.swift | 18 ++++++++++++++---- Rectangle/ApplicationToggle.swift | 12 ++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Rectangle/AppDelegate.swift b/Rectangle/AppDelegate.swift index 70eece45..e278cba0 100644 --- a/Rectangle/AppDelegate.swift +++ b/Rectangle/AppDelegate.swift @@ -239,9 +239,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { @IBAction func ignoreFrontMostApp(_ sender: NSMenuItem) { if sender.state == .on { - applicationToggle.enableFrontApp() + applicationToggle.enableApp() } else { - applicationToggle.disableFrontApp() + applicationToggle.disableApp() } } @@ -555,6 +555,15 @@ extension AppDelegate { func getUrlName(_ name: String) -> String { return name.map { $0.isUppercase ? "-" + $0.lowercased() : String($0) }.joined() } + func getAppBundleId(_ components: URLComponents) -> String? { + let appBundleIdParam = (components.queryItems?.first { $0.name == "app-bundle-id" }) + // if param not present the behavior is to use front app + return if let appBundleIdParam { + appBundleIdParam.value + } else { + ApplicationToggle.frontAppId + } + } for url in urls { guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true), @@ -564,14 +573,15 @@ extension AppDelegate { } let name = (components.queryItems?.first { $0.name == "name" })?.value + let appBundleId = getAppBundleId(components) switch (components.host, name) { case ("execute-action", _): let action = (WindowAction.active.first { getUrlName($0.name) == name }) action?.postUrl() case ("execute-task", "ignore-app"): - self.applicationToggle.disableFrontApp() + self.applicationToggle.disableApp(appBundleId: appBundleId) case ("execute-task", "unignore-app"): - self.applicationToggle.enableFrontApp() + self.applicationToggle.enableApp(appBundleId: appBundleId) default: continue } diff --git a/Rectangle/ApplicationToggle.swift b/Rectangle/ApplicationToggle.swift index f442760d..7c05875a 100644 --- a/Rectangle/ApplicationToggle.swift +++ b/Rectangle/ApplicationToggle.swift @@ -73,17 +73,17 @@ class ApplicationToggle: NSObject { } } - public func disableFrontApp() { - if let frontAppId = Self.frontAppId { - disabledApps.insert(frontAppId) + public func disableApp(appBundleId: String? = frontAppId) { + if let appBundleId { + disabledApps.insert(appBundleId) saveDisabledApps() disableShortcuts() } } - public func enableFrontApp() { - if let frontAppId = Self.frontAppId { - disabledApps.remove(frontAppId) + public func enableApp(appBundleId: String? = frontAppId) { + if let appBundleId { + disabledApps.remove(appBundleId) saveDisabledApps() enableShortcuts() } From 1304d0a3838b2e45f6d0caefbdf651d4343b48be Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 31 Oct 2024 20:01:58 +0100 Subject: [PATCH 5/6] PR Review --- Rectangle/AppDelegate.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Rectangle/AppDelegate.swift b/Rectangle/AppDelegate.swift index e278cba0..0d76771f 100644 --- a/Rectangle/AppDelegate.swift +++ b/Rectangle/AppDelegate.swift @@ -556,10 +556,10 @@ extension AppDelegate { return name.map { $0.isUppercase ? "-" + $0.lowercased() : String($0) }.joined() } func getAppBundleId(_ components: URLComponents) -> String? { - let appBundleIdParam = (components.queryItems?.first { $0.name == "app-bundle-id" }) - // if param not present the behavior is to use front app - return if let appBundleIdParam { - appBundleIdParam.value + let appBundleId = (components.queryItems?.first { $0.name == "app-bundle-id" })?.value + Logger.log("The app Bundle id : \(appBundleId ?? "")") + return if appBundleId != nil && appBundleId!.isEmpty { + appBundleId } else { ApplicationToggle.frontAppId } @@ -573,15 +573,14 @@ extension AppDelegate { } let name = (components.queryItems?.first { $0.name == "name" })?.value - let appBundleId = getAppBundleId(components) switch (components.host, name) { case ("execute-action", _): let action = (WindowAction.active.first { getUrlName($0.name) == name }) action?.postUrl() case ("execute-task", "ignore-app"): - self.applicationToggle.disableApp(appBundleId: appBundleId) + self.applicationToggle.disableApp(appBundleId: getAppBundleId(components)) case ("execute-task", "unignore-app"): - self.applicationToggle.enableApp(appBundleId: appBundleId) + self.applicationToggle.enableApp(appBundleId: getAppBundleId(components)) default: continue } From d1c7b04514ecce3cc8c9afc82869c05dc76de743 Mon Sep 17 00:00:00 2001 From: Ryan Hanson Date: Tue, 12 Nov 2024 22:01:30 -0800 Subject: [PATCH 6/6] Check if app-bundle-id parameter is empty for ignore/unignore url --- Rectangle/AppDelegate.swift | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Rectangle/AppDelegate.swift b/Rectangle/AppDelegate.swift index 0d76771f..6871e023 100644 --- a/Rectangle/AppDelegate.swift +++ b/Rectangle/AppDelegate.swift @@ -552,18 +552,23 @@ extension AppDelegate { prevActiveApp?.activate() } DispatchQueue.main.async { + func getUrlName(_ name: String) -> String { return name.map { $0.isUppercase ? "-" + $0.lowercased() : String($0) }.joined() } - func getAppBundleId(_ components: URLComponents) -> String? { - let appBundleId = (components.queryItems?.first { $0.name == "app-bundle-id" })?.value - Logger.log("The app Bundle id : \(appBundleId ?? "")") - return if appBundleId != nil && appBundleId!.isEmpty { - appBundleId - } else { - ApplicationToggle.frontAppId + + func extractBundleIdParameter(fromComponents components: URLComponents) -> String? { + (components.queryItems?.first { $0.name == "app-bundle-id" })?.value + } + + func isValidParameter(bundleId: String?) -> Bool { + let isValid = bundleId?.isEmpty != true + if !isValid { + Logger.log("Received an empty app-bundle-id parameter. Either pass a valid app bundle id or remove the parameter.") } + return isValid } + for url in urls { guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true), @@ -578,9 +583,13 @@ extension AppDelegate { let action = (WindowAction.active.first { getUrlName($0.name) == name }) action?.postUrl() case ("execute-task", "ignore-app"): - self.applicationToggle.disableApp(appBundleId: getAppBundleId(components)) + let bundleId = extractBundleIdParameter(fromComponents: components) + guard isValidParameter(bundleId: bundleId) else { continue } + self.applicationToggle.disableApp(appBundleId: bundleId) case ("execute-task", "unignore-app"): - self.applicationToggle.enableApp(appBundleId: getAppBundleId(components)) + let bundleId = extractBundleIdParameter(fromComponents: components) + guard isValidParameter(bundleId: bundleId) else { continue } + self.applicationToggle.enableApp(appBundleId: bundleId) default: continue }