From 6f21dd9317cc1b8dddf3efab86d0e93cf4e5bf07 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 4 Sep 2024 12:50:47 +0200 Subject: [PATCH 1/8] feat(shortcuts): create AppIntents.swift --- IVPNClient.xcodeproj/project.pbxproj | 4 ++ IVPNClient/Models/AppIntents.swift | 49 +++++++++++++++++++ .../MainScreen/MainViewController.swift | 23 +++++++++ .../Extensions/NotificationName+Ext.swift | 6 +++ 4 files changed, 82 insertions(+) create mode 100644 IVPNClient/Models/AppIntents.swift diff --git a/IVPNClient.xcodeproj/project.pbxproj b/IVPNClient.xcodeproj/project.pbxproj index 623991b6c..b6f00724f 100644 --- a/IVPNClient.xcodeproj/project.pbxproj +++ b/IVPNClient.xcodeproj/project.pbxproj @@ -267,6 +267,7 @@ 82DB75EE239E766A0073E846 /* NEVPNStatusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DB75ED239E766A0073E846 /* NEVPNStatusTests.swift */; }; 82DC75BC22B277D200D3C73C /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DC75BB22B277D200D3C73C /* APIClient.swift */; }; 82DC75BD22B7647500D3C73C /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DC75BB22B277D200D3C73C /* APIClient.swift */; }; + 82DE85712C8861CB00501935 /* AppIntents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DE85702C8861CB00501935 /* AppIntents.swift */; }; 82DEF01E244714D900CCB5CD /* ScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEF01D244714D900CCB5CD /* ScannerViewController.swift */; }; 82DEF021244714F000CCB5CD /* ScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEF020244714F000CCB5CD /* ScannerView.swift */; }; 82DEF0262447285F00CCB5CD /* CreateAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEF0252447285F00CCB5CD /* CreateAccountViewController.swift */; }; @@ -674,6 +675,7 @@ 82DB75EB239E75EB0073E846 /* NEVPNStatus+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEVPNStatus+Ext.swift"; sourceTree = ""; }; 82DB75ED239E766A0073E846 /* NEVPNStatusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NEVPNStatusTests.swift; sourceTree = ""; }; 82DC75BB22B277D200D3C73C /* APIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIClient.swift; sourceTree = ""; }; + 82DE85702C8861CB00501935 /* AppIntents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntents.swift; sourceTree = ""; }; 82DEF01D244714D900CCB5CD /* ScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerViewController.swift; sourceTree = ""; }; 82DEF020244714F000CCB5CD /* ScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerView.swift; sourceTree = ""; }; 82DEF0252447285F00CCB5CD /* CreateAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountViewController.swift; sourceTree = ""; }; @@ -1032,6 +1034,7 @@ 827694F2263C04C40058B4DC /* LoginConfirmation.swift */, 821CA2DE288143470067F70D /* PortRange.swift */, 825ECB2B2A5582570032E986 /* AntiTrackerDns.swift */, + 82DE85702C8861CB00501935 /* AppIntents.swift */, ); path = Models; sourceTree = ""; @@ -2392,6 +2395,7 @@ 82DEF01E244714D900CCB5CD /* ScannerViewController.swift in Sources */, 8270D268241BB3D100B17B65 /* InfoAlertViewModel.swift in Sources */, 826E614A242A1CA80064F195 /* AccountViewModel.swift in Sources */, + 82DE85712C8861CB00501935 /* AppIntents.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/IVPNClient/Models/AppIntents.swift b/IVPNClient/Models/AppIntents.swift new file mode 100644 index 000000000..5e0d76836 --- /dev/null +++ b/IVPNClient/Models/AppIntents.swift @@ -0,0 +1,49 @@ +// +// AddNoteIntent.swift +// IVPN iOS app +// https://github.com/ivpn/ios-app +// +// Created by Juraj Hilje on 2024-09-04. +// Copyright (c) 2024 IVPN Limited. +// +// This file is part of the IVPN iOS app. +// +// The IVPN iOS app is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// The IVPN iOS app is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License +// along with the IVPN iOS app. If not, see . +// + + +import AppIntents + +@available(iOS 16, *) +struct AntiTrackerEnable: AppIntent { + static var title = LocalizedStringResource("Enable AntiTracker") + static var description = IntentDescription("Enables the AntiTracker") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: EnableAntiTracker") + NotificationCenter.default.post(name: Notification.Name.IntentEnaableAntiTracker, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct AntiTrackerDisable: AppIntent { + static var title = LocalizedStringResource("Disable AntiTracker") + static var description = IntentDescription("Disables the AntiTracker") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: DisableAntiTracker") + NotificationCenter.default.post(name: Notification.Name.IntentDisableAntiTracker, object: nil) + return .result() + } +} diff --git a/IVPNClient/Scenes/MainScreen/MainViewController.swift b/IVPNClient/Scenes/MainScreen/MainViewController.swift index efaa9804d..bb22e0b2a 100644 --- a/IVPNClient/Scenes/MainScreen/MainViewController.swift +++ b/IVPNClient/Scenes/MainScreen/MainViewController.swift @@ -198,6 +198,29 @@ class MainViewController: UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(vpnConfigurationDisabled), name: Notification.Name.VPNConfigurationDisabled, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(subscriptionActivated), name: Notification.Name.SubscriptionActivated, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateGeoLocation), name: Notification.Name.UpdateGeoLocation, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentAntiTrackerEnable), name: Notification.Name.IntentAntiTrackerEnable, object: nil) + } + + // MARK: - App Intents - + + @objc func intentAntiTrackerEnable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + viewController.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in + } + return + } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } } // MARK: - Private methods - diff --git a/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift b/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift index dd63512ec..0d8565aa7 100644 --- a/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift +++ b/IVPNClient/Utilities/Extensions/NotificationName+Ext.swift @@ -58,5 +58,11 @@ extension Notification.Name { public static let CustomDNSUpdated = Notification.Name("customDNSUpdatedUpdated") public static let EvaluateReconnect = Notification.Name("evaluateReconnect") public static let EvaluatePlanUpdate = Notification.Name("evaluatePlanUpdate") + public static let IntentConnect = Notification.Name("intentConnect") + public static let IntentDisconnect = Notification.Name("intentDisconnect") + public static let IntentAntiTrackerEnable = Notification.Name("intentAntiTrackerEnable") + public static let IntentAntiTrackerDisable = Notification.Name("intentAntiTrackerDisable") + public static let IntentCustomDNSEnable = Notification.Name("intentCustomDNSEnable") + public static let IntentCustomDNSDisable = Notification.Name("intentCustomDNSDisable") } From d2c5b0d09b9fcecf57a646a9d9559af168ae351d Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 4 Sep 2024 13:11:28 +0200 Subject: [PATCH 2/8] feat(shortcuts): create AppIntentsHandler.swift --- IVPNClient.xcodeproj/project.pbxproj | 4 + IVPNClient/Models/AppIntents.swift | 52 ++++++++- .../Scenes/MainScreen/AppIntentsHandler.swift | 106 ++++++++++++++++++ .../MainScreen/MainViewController.swift | 27 +---- 4 files changed, 165 insertions(+), 24 deletions(-) create mode 100644 IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift diff --git a/IVPNClient.xcodeproj/project.pbxproj b/IVPNClient.xcodeproj/project.pbxproj index b6f00724f..b0e009176 100644 --- a/IVPNClient.xcodeproj/project.pbxproj +++ b/IVPNClient.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ 828772F7221C008100D5E330 /* ServerConfigurationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828772F6221C008100D5E330 /* ServerConfigurationCell.swift */; }; 828772F9221C01C300D5E330 /* ServersConfigurationTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828772F8221C01C300D5E330 /* ServersConfigurationTableViewController.swift */; }; 828772FB221C28E000D5E330 /* FlagImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828772FA221C28E000D5E330 /* FlagImageView.swift */; }; + 828C45692C88772E0064F365 /* AppIntentsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828C45682C8877290064F365 /* AppIntentsHandler.swift */; }; 828D8A6D258245AD00CB0E5B /* TwoFactorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828D8A6C258245AD00CB0E5B /* TwoFactorViewController.swift */; }; 828E9C95231E5780001E1FCF /* Data+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828E9C94231E5780001E1FCF /* Data+Ext.swift */; }; 828E9C96231E5780001E1FCF /* Data+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828E9C94231E5780001E1FCF /* Data+Ext.swift */; }; @@ -588,6 +589,7 @@ 828772F6221C008100D5E330 /* ServerConfigurationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfigurationCell.swift; sourceTree = ""; }; 828772F8221C01C300D5E330 /* ServersConfigurationTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersConfigurationTableViewController.swift; sourceTree = ""; }; 828772FA221C28E000D5E330 /* FlagImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlagImageView.swift; sourceTree = ""; }; + 828C45682C8877290064F365 /* AppIntentsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentsHandler.swift; sourceTree = ""; }; 828D8A6C258245AD00CB0E5B /* TwoFactorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoFactorViewController.swift; sourceTree = ""; }; 828E9C94231E5780001E1FCF /* Data+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Ext.swift"; sourceTree = ""; }; 8290195E243CB27500777B6E /* ControlPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlPanelView.swift; sourceTree = ""; }; @@ -927,6 +929,7 @@ 82C1D5BD23FE8BD90059A915 /* ControlPanel */, 8208525723FD5EB20008C112 /* MainViewController.swift */, 8208525B23FD64160008C112 /* MainViewController+Ext.swift */, + 828C45682C8877290064F365 /* AppIntentsHandler.swift */, ); path = MainScreen; sourceTree = ""; @@ -2337,6 +2340,7 @@ 8292E1A92174C11600123538 /* Interface.swift in Sources */, 82F638CC217DC25600410318 /* CIDRAddress.swift in Sources */, 824B86D226D40E7800D0101A /* FileManager+Extension.swift in Sources */, + 828C45692C88772E0064F365 /* AppIntentsHandler.swift in Sources */, 8208525A23FD5F670008C112 /* FloatingPanelController+Ext.swift in Sources */, 821429B722FC2BE90056B8FF /* Result.swift in Sources */, 827855B92472B27F00B3B6BD /* Account.swift in Sources */, diff --git a/IVPNClient/Models/AppIntents.swift b/IVPNClient/Models/AppIntents.swift index 5e0d76836..83879e37d 100644 --- a/IVPNClient/Models/AppIntents.swift +++ b/IVPNClient/Models/AppIntents.swift @@ -24,6 +24,30 @@ import AppIntents +@available(iOS 16, *) +struct Connect: AppIntent { + static var title = LocalizedStringResource("Connect") + static var description = IntentDescription("Connect to the VPN") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: Connect") + NotificationCenter.default.post(name: Notification.Name.IntentConnect, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct Disconnect: AppIntent { + static var title = LocalizedStringResource("Disconnect") + static var description = IntentDescription("Disconnect from the VPN") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: Disconnect") + NotificationCenter.default.post(name: Notification.Name.IntentDisconnect, object: nil) + return .result() + } +} + @available(iOS 16, *) struct AntiTrackerEnable: AppIntent { static var title = LocalizedStringResource("Enable AntiTracker") @@ -31,7 +55,7 @@ struct AntiTrackerEnable: AppIntent { func perform() async throws -> some IntentResult { log(.info, message: "App Intent handler: EnableAntiTracker") - NotificationCenter.default.post(name: Notification.Name.IntentEnaableAntiTracker, object: nil) + NotificationCenter.default.post(name: Notification.Name.IntentAntiTrackerEnable, object: nil) return .result() } } @@ -43,7 +67,31 @@ struct AntiTrackerDisable: AppIntent { func perform() async throws -> some IntentResult { log(.info, message: "App Intent handler: DisableAntiTracker") - NotificationCenter.default.post(name: Notification.Name.IntentDisableAntiTracker, object: nil) + NotificationCenter.default.post(name: Notification.Name.IntentAntiTrackerDisable, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct CustomDNSEnable: AppIntent { + static var title = LocalizedStringResource("Enable Custom DNS") + static var description = IntentDescription("Enables the Custom DNS") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: EnableCustomDNS") + NotificationCenter.default.post(name: Notification.Name.IntentCustomDNSEnable, object: nil) + return .result() + } +} + +@available(iOS 16, *) +struct CustomDNSDisable: AppIntent { + static var title = LocalizedStringResource("Disable Custom DNS") + static var description = IntentDescription("Disables the Custom DNS") + + func perform() async throws -> some IntentResult { + log(.info, message: "App Intent handler: DisableCustomDNS") + NotificationCenter.default.post(name: Notification.Name.IntentCustomDNSDisable, object: nil) return .result() } } diff --git a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift new file mode 100644 index 000000000..a9744dee1 --- /dev/null +++ b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift @@ -0,0 +1,106 @@ +// +// AppIntentsHandler.swift +// IVPNClient +// +// Created by Juraj Hilje on 04.09.2024.. +// Copyright © 2024 IVPN. All rights reserved. +// + +extension MainViewController { + + // MARK: - App Intents - + + @objc func intentConnect() { + DispatchQueue.delay(0.75) { + if UserDefaults.shared.networkProtectionEnabled { + Application.shared.connectionManager.resetRulesAndConnectShortcut(closeApp: true, actionType: .connect) + return + } + Application.shared.connectionManager.connectShortcut(closeApp: true, actionType: .connect) + } + } + + @objc func intentDisconnect() { + DispatchQueue.delay(0.75) { + if UserDefaults.shared.networkProtectionEnabled { + Application.shared.connectionManager.resetRulesAndDisconnectShortcut(closeApp: true, actionType: .disconnect) + return + } + Application.shared.connectionManager.disconnectShortcut(closeApp: true, actionType: .disconnect) + } + } + + @objc func intentAntiTrackerEnable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + viewController.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in + } + return + } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + + @objc func intentAntiTrackerDisable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + + @objc func intentCustomDNSEnable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + viewController.showAlert(title: "IKEv2 not supported", message: "Custom DNS is supported only for OpenVPN and WireGuard protocols.") { _ in + } + return + } + + guard !UserDefaults.shared.customDNS.isEmpty else { + viewController.showAlert(title: "", message: "Please enter DNS server info") + return + } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + + @objc func intentCustomDNSDisable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + +} diff --git a/IVPNClient/Scenes/MainScreen/MainViewController.swift b/IVPNClient/Scenes/MainScreen/MainViewController.swift index bb22e0b2a..80e94f7fb 100644 --- a/IVPNClient/Scenes/MainScreen/MainViewController.swift +++ b/IVPNClient/Scenes/MainScreen/MainViewController.swift @@ -198,29 +198,12 @@ class MainViewController: UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(vpnConfigurationDisabled), name: Notification.Name.VPNConfigurationDisabled, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(subscriptionActivated), name: Notification.Name.SubscriptionActivated, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateGeoLocation), name: Notification.Name.UpdateGeoLocation, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentConnect), name: Notification.Name.IntentConnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentDisconnect), name: Notification.Name.IntentDisconnect, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(intentAntiTrackerEnable), name: Notification.Name.IntentAntiTrackerEnable, object: nil) - } - - // MARK: - App Intents - - - @objc func intentAntiTrackerEnable() { - DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { - viewController.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in - } - return - } - - UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) - NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) - } - } - } + NotificationCenter.default.addObserver(self, selector: #selector(intentAntiTrackerDisable), name: Notification.Name.IntentAntiTrackerDisable, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentCustomDNSEnable), name: Notification.Name.IntentCustomDNSEnable, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(intentCustomDNSDisable), name: Notification.Name.IntentCustomDNSDisable, object: nil) } // MARK: - Private methods - From 9bc236ed271a92855d36f43e17dc90cb2e26e4f4 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 4 Sep 2024 13:16:28 +0200 Subject: [PATCH 3/8] feat(shortcuts): update AppDelegate.swift --- IVPNClient.xcodeproj/project.pbxproj | 8 -- IVPNClient/AppDelegate.swift | 124 ------------------ IVPNClient/Enums/UserActivityTitle.swift | 33 ----- IVPNClient/Enums/UserActivityType.swift | 33 ----- .../ControlPanelViewController.swift | 10 -- .../AntiTrackerViewController.swift | 6 - .../CustomDNSViewController.swift | 6 - .../Extensions/UIViewController+Ext.swift | 10 -- 8 files changed, 230 deletions(-) delete mode 100644 IVPNClient/Enums/UserActivityTitle.swift delete mode 100644 IVPNClient/Enums/UserActivityType.swift diff --git a/IVPNClient.xcodeproj/project.pbxproj b/IVPNClient.xcodeproj/project.pbxproj index b0e009176..4fd94b4f5 100644 --- a/IVPNClient.xcodeproj/project.pbxproj +++ b/IVPNClient.xcodeproj/project.pbxproj @@ -25,8 +25,6 @@ 8206BAFF29ED6FFF00F916B7 /* ConnectionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206BAFE29ED6FFF00F916B7 /* ConnectionInfoView.swift */; }; 8206BB0129ED7BEE00F916B7 /* ConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206BB0029ED7BEE00F916B7 /* ConnectionInfo.swift */; }; 8206BB0329ED7C3700F916B7 /* ConnectionInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206BB0229ED7C3700F916B7 /* ConnectionInfoViewModel.swift */; }; - 8206E5D022967E37003119AF /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206E5CF22967E37003119AF /* UserActivityType.swift */; }; - 8206E5D222967EAF003119AF /* UserActivityTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206E5D122967EAF003119AF /* UserActivityTitle.swift */; }; 8206F32124347A8F0056B465 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206F32024347A8F0056B465 /* MainView.swift */; }; 8206F32324367A240056B465 /* VPNErrorObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8206F32224367A240056B465 /* VPNErrorObserver.swift */; }; 8208525623FD56870008C112 /* FloatingPanelMainLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8208525523FD56870008C112 /* FloatingPanelMainLayout.swift */; }; @@ -473,8 +471,6 @@ 8206BAFE29ED6FFF00F916B7 /* ConnectionInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionInfoView.swift; sourceTree = ""; }; 8206BB0029ED7BEE00F916B7 /* ConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionInfo.swift; sourceTree = ""; }; 8206BB0229ED7C3700F916B7 /* ConnectionInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionInfoViewModel.swift; sourceTree = ""; }; - 8206E5CF22967E37003119AF /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = ""; }; - 8206E5D122967EAF003119AF /* UserActivityTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityTitle.swift; sourceTree = ""; }; 8206F32024347A8F0056B465 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 8206F32224367A240056B465 /* VPNErrorObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNErrorObserver.swift; sourceTree = ""; }; 8208525523FD56870008C112 /* FloatingPanelMainLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelMainLayout.swift; sourceTree = ""; }; @@ -1198,8 +1194,6 @@ 82E716832181E8E100D6B7C2 /* ProviderConfigurationKeys.swift */, 82D598B321A5A7A3000FABDE /* NetworkTrust.swift */, 82D598C721A6ADF1000FABDE /* NetworkType.swift */, - 8206E5CF22967E37003119AF /* UserActivityType.swift */, - 8206E5D122967EAF003119AF /* UserActivityTitle.swift */, 823FFB062338DF1800F91A5D /* Capability.swift */, 8229209F2480FA3600476FC1 /* ServersSort.swift */, 826FBDA22461847D00B9E464 /* ServiceType.swift */, @@ -2291,7 +2285,6 @@ 82D598BC21A6949F000FABDE /* StorageManager.swift in Sources */, 826FBDA32461847D00B9E464 /* ServiceType.swift in Sources */, 821429B922FC2EA40056B8FF /* ApiService+Ext.swift in Sources */, - 8206E5D222967EAF003119AF /* UserActivityTitle.swift in Sources */, 82E716902181E90500D6B7C2 /* ConnectionSettings.swift in Sources */, 8223C54C22E9E93A00CD283D /* Session.swift in Sources */, 822563922431E03A00AE7F8D /* AccountView.swift in Sources */, @@ -2364,7 +2357,6 @@ 82A3422524AB6AF700761AB0 /* Double+Ext.swift in Sources */, 8221377B2227E75E001E1BF5 /* CustomDNSViewController.swift in Sources */, 9C3031351DB42EF900C38B0C /* Application.swift in Sources */, - 8206E5D022967E37003119AF /* UserActivityType.swift in Sources */, 82A6D74A24A3780B00D6C0E1 /* ConnectToServerPopupView.swift in Sources */, 828772FB221C28E000D5E330 /* FlagImageView.swift in Sources */, 8228C8D22B1DE906005977D3 /* PurchaseManager.swift in Sources */, diff --git a/IVPNClient/AppDelegate.swift b/IVPNClient/AppDelegate.swift index 1753b0197..8285dff0e 100644 --- a/IVPNClient/AppDelegate.swift +++ b/IVPNClient/AppDelegate.swift @@ -178,99 +178,6 @@ class AppDelegate: UIResponder { } } - private func userActivityConnect() { - DispatchQueue.delay(0.75) { - if UserDefaults.shared.networkProtectionEnabled { - Application.shared.connectionManager.resetRulesAndConnectShortcut(closeApp: true, actionType: .connect) - return - } - Application.shared.connectionManager.connectShortcut(closeApp: true, actionType: .connect) - } - } - - private func userActivityDisconnect() { - DispatchQueue.delay(0.75) { - if UserDefaults.shared.networkProtectionEnabled { - Application.shared.connectionManager.resetRulesAndDisconnectShortcut(closeApp: true, actionType: .disconnect) - return - } - Application.shared.connectionManager.disconnectShortcut(closeApp: true, actionType: .disconnect) - } - } - - private func userActivityAntiTrackerEnable() { - DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { - viewController.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in - } - return - } - - UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) - NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) - } - } - } - } - - private func userActivityAntiTrackerDisable() { - DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - UserDefaults.shared.set(false, forKey: UserDefaults.Key.isAntiTracker) - NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) - } - } - } - } - - private func userActivityCustomDNSEnable() { - DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { - viewController.showAlert(title: "IKEv2 not supported", message: "Custom DNS is supported only for OpenVPN and WireGuard protocols.") { _ in - } - return - } - - guard !UserDefaults.shared.customDNS.isEmpty else { - viewController.showAlert(title: "", message: "Please enter DNS server info") - return - } - - UserDefaults.shared.set(true, forKey: UserDefaults.Key.isCustomDNS) - NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) - } - } - } - } - - private func userActivityCustomDNSDisable() { - DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - UserDefaults.shared.set(false, forKey: UserDefaults.Key.isCustomDNS) - NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) - } - } - } - } - private func startPurchaseObserver() { PurchaseManager.shared.delegate = self PurchaseManager.shared.startObserver() @@ -361,37 +268,6 @@ extension AppDelegate: UIApplicationDelegate { return true } - func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { - if let url = userActivity.webpageURL { - let endpoint = url.lastPathComponent - handleURLEndpoint(endpoint) - return false - } - - guard Application.shared.authentication.isLoggedIn, Application.shared.serviceStatus.isActive else { - return false - } - - switch userActivity.activityType { - case UserActivityType.Connect: - userActivityConnect() - case UserActivityType.Disconnect: - userActivityDisconnect() - case UserActivityType.AntiTrackerEnable: - userActivityAntiTrackerEnable() - case UserActivityType.AntiTrackerDisable: - userActivityAntiTrackerDisable() - case UserActivityType.CustomDNSEnable: - userActivityCustomDNSEnable() - case UserActivityType.CustomDNSDisable: - userActivityCustomDNSDisable() - default: - log(.info, message: "No such user activity") - } - - return false - } - } // MARK: - PurchaseManagerDelegate - diff --git a/IVPNClient/Enums/UserActivityTitle.swift b/IVPNClient/Enums/UserActivityTitle.swift deleted file mode 100644 index 74c4590fb..000000000 --- a/IVPNClient/Enums/UserActivityTitle.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// UserActivityTitle.swift -// IVPN iOS app -// https://github.com/ivpn/ios-app -// -// Created by Juraj Hilje on 2019-05-23. -// Copyright (c) 2023 IVPN Limited. -// -// This file is part of the IVPN iOS app. -// -// The IVPN iOS app is free software: you can redistribute it and/or -// modify it under the terms of the GNU General Public License as published by the Free -// Software Foundation, either version 3 of the License, or (at your option) any later version. -// -// The IVPN iOS app is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License -// along with the IVPN iOS app. If not, see . -// - -import Foundation - -enum UserActivityTitle { - static let Connect = "Connect" - static let Disconnect = "Disconnect" - static let AntiTrackerEnable = "Enable AntiTracker" - static let AntiTrackerDisable = "Disable AntiTracker" - static let CustomDNSEnable = "Enable CustomDNS" - static let CustomDNSDisable = "Disable CustomDNS" -} diff --git a/IVPNClient/Enums/UserActivityType.swift b/IVPNClient/Enums/UserActivityType.swift deleted file mode 100644 index d0be60601..000000000 --- a/IVPNClient/Enums/UserActivityType.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// UserActivityType.swift -// IVPN iOS app -// https://github.com/ivpn/ios-app -// -// Created by Juraj Hilje on 2019-05-23. -// Copyright (c) 2023 IVPN Limited. -// -// This file is part of the IVPN iOS app. -// -// The IVPN iOS app is free software: you can redistribute it and/or -// modify it under the terms of the GNU General Public License as published by the Free -// Software Foundation, either version 3 of the License, or (at your option) any later version. -// -// The IVPN iOS app is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License -// along with the IVPN iOS app. If not, see . -// - -import Foundation - -enum UserActivityType { - static let Connect = "net.ivpn.clients.ios.Connect" - static let Disconnect = "net.ivpn.clients.ios.Disconnect" - static let AntiTrackerEnable = "net.ivpn.clients.ios.AntiTracker.enable" - static let AntiTrackerDisable = "net.ivpn.clients.ios.AntiTracker.disable" - static let CustomDNSEnable = "net.ivpn.clients.ios.CustomDNS.enable" - static let CustomDNSDisable = "net.ivpn.clients.ios.CustomDNS.disable" -} diff --git a/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift b/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift index 12ec8e37d..dbfb5043f 100644 --- a/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift +++ b/IVPNClient/Scenes/MainScreen/ControlPanel/ControlPanelViewController.swift @@ -108,12 +108,6 @@ class ControlPanelViewController: UITableViewController { WidgetCenter.shared.reloadTimelines(ofKind: "IVPNWidget") evaluateReconnect(sender: sender as UIView) controlPanelView.updateAntiTracker(viewModel: vpnStatusViewModel) - - if sender.isOn { - registerUserActivity(type: UserActivityType.AntiTrackerEnable, title: UserActivityTitle.AntiTrackerEnable) - } else { - registerUserActivity(type: UserActivityType.AntiTrackerDisable, title: UserActivityTitle.AntiTrackerDisable) - } } @IBAction func selectIpProtocol(_ sender: UISegmentedControl) { @@ -223,8 +217,6 @@ class ControlPanelViewController: UITableViewController { manager.resetRulesAndConnect() } - registerUserActivity(type: UserActivityType.Connect, title: UserActivityTitle.Connect) - NotificationCenter.default.removeObserver(self, name: Notification.Name.ServiceAuthorized, object: nil) NotificationCenter.default.removeObserver(self, name: Notification.Name.SubscriptionActivated, object: nil) } @@ -240,8 +232,6 @@ class ControlPanelViewController: UITableViewController { manager.resetRulesAndDisconnect() } - registerUserActivity(type: UserActivityType.Disconnect, title: UserActivityTitle.Disconnect) - DispatchQueue.delay(0.5) { if Application.shared.connectionManager.status.isDisconnected() { Pinger.shared.ping() diff --git a/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift b/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift index 4b4a518e5..3c35b036f 100644 --- a/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/AntiTrackerViewController.swift @@ -46,12 +46,6 @@ class AntiTrackerViewController: UITableViewController { antiTrackerHardcoreSwitch.isEnabled = sender.isOn evaluateReconnect(sender: sender as UIView) NotificationCenter.default.post(name: Notification.Name.UpdateControlPanel, object: nil) - - if sender.isOn { - registerUserActivity(type: UserActivityType.AntiTrackerEnable, title: UserActivityTitle.AntiTrackerEnable) - } else { - registerUserActivity(type: UserActivityType.AntiTrackerDisable, title: UserActivityTitle.AntiTrackerDisable) - } } @IBAction func toggleAntiTrackerHardcore(_ sender: UISwitch) { diff --git a/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift b/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift index bf86e317a..2fcbe5a3d 100644 --- a/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/CustomDNSViewController.swift @@ -53,12 +53,6 @@ class CustomDNSViewController: UITableViewController { UserDefaults.shared.set(sender.isOn, forKey: UserDefaults.Key.isCustomDNS) evaluateReconnect(sender: sender) - - if sender.isOn { - registerUserActivity(type: UserActivityType.CustomDNSEnable, title: UserActivityTitle.CustomDNSEnable) - } else { - registerUserActivity(type: UserActivityType.CustomDNSDisable, title: UserActivityTitle.CustomDNSDisable) - } } @IBAction func enableSecureDNS(_ sender: UISwitch) { diff --git a/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift b/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift index 362af3e8c..9f1705d21 100644 --- a/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift +++ b/IVPNClient/Utilities/Extensions/UIViewController+Ext.swift @@ -95,16 +95,6 @@ extension UIViewController { openWebPage("https://www.ivpn.net/privacy-mobile-app/") } - func registerUserActivity(type: String, title: String) { - let activity = NSUserActivity(activityType: type) - activity.title = title - activity.isEligibleForSearch = true - activity.isEligibleForPrediction = true - - userActivity = activity - userActivity?.becomeCurrent() - } - func hideKeyboardOnTap() { let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard)) tap.cancelsTouchesInView = false From 1a9f79584b87907970bd133e963b04fc0b375a06 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 4 Sep 2024 13:27:19 +0200 Subject: [PATCH 4/8] feat(shortcuts): update AppIntentsHandler.swift --- IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift index a9744dee1..5ddc83860 100644 --- a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift +++ b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift @@ -6,6 +6,8 @@ // Copyright © 2024 IVPN. All rights reserved. // +import UIKit + extension MainViewController { // MARK: - App Intents - From 5b431509b143ad6fc808d19c1ee97e2633e95684 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 4 Sep 2024 13:43:22 +0200 Subject: [PATCH 5/8] feat(shortcuts): update AppIntents.swift --- IVPNClient/Models/AppIntents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IVPNClient/Models/AppIntents.swift b/IVPNClient/Models/AppIntents.swift index 83879e37d..49d890d5a 100644 --- a/IVPNClient/Models/AppIntents.swift +++ b/IVPNClient/Models/AppIntents.swift @@ -26,7 +26,7 @@ import AppIntents @available(iOS 16, *) struct Connect: AppIntent { - static var title = LocalizedStringResource("Connect") + static var title = LocalizedStringResource("Connect VPN") static var description = IntentDescription("Connect to the VPN") func perform() async throws -> some IntentResult { @@ -38,7 +38,7 @@ struct Connect: AppIntent { @available(iOS 16, *) struct Disconnect: AppIntent { - static var title = LocalizedStringResource("Disconnect") + static var title = LocalizedStringResource("Disconnect VPN") static var description = IntentDescription("Disconnect from the VPN") func perform() async throws -> some IntentResult { From a2a8f7cdb0ebf0343005d74c39435e2b974138d9 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 4 Sep 2024 14:32:33 +0200 Subject: [PATCH 6/8] feat(shortcuts): update AppIntentsHandler.swift --- IVPNClient/AppDelegate.swift | 124 ++++++++++++++++++ .../Scenes/MainScreen/AppIntentsHandler.swift | 78 ++++------- 2 files changed, 151 insertions(+), 51 deletions(-) diff --git a/IVPNClient/AppDelegate.swift b/IVPNClient/AppDelegate.swift index 8285dff0e..1753b0197 100644 --- a/IVPNClient/AppDelegate.swift +++ b/IVPNClient/AppDelegate.swift @@ -178,6 +178,99 @@ class AppDelegate: UIResponder { } } + private func userActivityConnect() { + DispatchQueue.delay(0.75) { + if UserDefaults.shared.networkProtectionEnabled { + Application.shared.connectionManager.resetRulesAndConnectShortcut(closeApp: true, actionType: .connect) + return + } + Application.shared.connectionManager.connectShortcut(closeApp: true, actionType: .connect) + } + } + + private func userActivityDisconnect() { + DispatchQueue.delay(0.75) { + if UserDefaults.shared.networkProtectionEnabled { + Application.shared.connectionManager.resetRulesAndDisconnectShortcut(closeApp: true, actionType: .disconnect) + return + } + Application.shared.connectionManager.disconnectShortcut(closeApp: true, actionType: .disconnect) + } + } + + private func userActivityAntiTrackerEnable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + viewController.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in + } + return + } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + + private func userActivityAntiTrackerDisable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + + private func userActivityCustomDNSEnable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + viewController.showAlert(title: "IKEv2 not supported", message: "Custom DNS is supported only for OpenVPN and WireGuard protocols.") { _ in + } + return + } + + guard !UserDefaults.shared.customDNS.isEmpty else { + viewController.showAlert(title: "", message: "Please enter DNS server info") + return + } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + + private func userActivityCustomDNSDisable() { + DispatchQueue.async { + if let viewController = UIApplication.topViewController() { + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + if UIApplication.topViewController() as? MainViewController != nil { + NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) + } else { + viewController.evaluateReconnect(sender: viewController.view) + } + } + } + } + private func startPurchaseObserver() { PurchaseManager.shared.delegate = self PurchaseManager.shared.startObserver() @@ -268,6 +361,37 @@ extension AppDelegate: UIApplicationDelegate { return true } + func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + if let url = userActivity.webpageURL { + let endpoint = url.lastPathComponent + handleURLEndpoint(endpoint) + return false + } + + guard Application.shared.authentication.isLoggedIn, Application.shared.serviceStatus.isActive else { + return false + } + + switch userActivity.activityType { + case UserActivityType.Connect: + userActivityConnect() + case UserActivityType.Disconnect: + userActivityDisconnect() + case UserActivityType.AntiTrackerEnable: + userActivityAntiTrackerEnable() + case UserActivityType.AntiTrackerDisable: + userActivityAntiTrackerDisable() + case UserActivityType.CustomDNSEnable: + userActivityCustomDNSEnable() + case UserActivityType.CustomDNSDisable: + userActivityCustomDNSDisable() + default: + log(.info, message: "No such user activity") + } + + return false + } + } // MARK: - PurchaseManagerDelegate - diff --git a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift index 5ddc83860..9e25095ab 100644 --- a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift +++ b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift @@ -18,7 +18,7 @@ extension MainViewController { Application.shared.connectionManager.resetRulesAndConnectShortcut(closeApp: true, actionType: .connect) return } - Application.shared.connectionManager.connectShortcut(closeApp: true, actionType: .connect) + Application.shared.connectionManager.connect() } } @@ -28,80 +28,56 @@ extension MainViewController { Application.shared.connectionManager.resetRulesAndDisconnectShortcut(closeApp: true, actionType: .disconnect) return } - Application.shared.connectionManager.disconnectShortcut(closeApp: true, actionType: .disconnect) + Application.shared.connectionManager.disconnect() } } @objc func intentAntiTrackerEnable() { DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { - viewController.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in - } - return - } - - UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) - NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + self.showAlert(title: "IKEv2 not supported", message: "AntiTracker is supported only for OpenVPN and WireGuard protocols.") { _ in } + return } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + self.evaluateReconnect(sender: self.view) } } @objc func intentAntiTrackerDisable() { DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - UserDefaults.shared.set(false, forKey: UserDefaults.Key.isAntiTracker) - NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) - } - } + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isAntiTracker) + NotificationCenter.default.post(name: Notification.Name.AntiTrackerUpdated, object: nil) + self.evaluateReconnect(sender: self.view) } } @objc func intentCustomDNSEnable() { DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { - viewController.showAlert(title: "IKEv2 not supported", message: "Custom DNS is supported only for OpenVPN and WireGuard protocols.") { _ in - } - return - } - - guard !UserDefaults.shared.customDNS.isEmpty else { - viewController.showAlert(title: "", message: "Please enter DNS server info") - return - } - - UserDefaults.shared.set(true, forKey: UserDefaults.Key.isCustomDNS) - NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) + if Application.shared.settings.connectionProtocol.tunnelType() == .ipsec { + self.showAlert(title: "IKEv2 not supported", message: "Custom DNS is supported only for OpenVPN and WireGuard protocols.") { _ in } + return + } + + guard !UserDefaults.shared.customDNS.isEmpty else { + self.showAlert(title: "", message: "Please enter DNS server info") + return } + + UserDefaults.shared.set(true, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + self.evaluateReconnect(sender: self.view) } } @objc func intentCustomDNSDisable() { DispatchQueue.async { - if let viewController = UIApplication.topViewController() { - UserDefaults.shared.set(false, forKey: UserDefaults.Key.isCustomDNS) - NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) - if UIApplication.topViewController() as? MainViewController != nil { - NotificationCenter.default.post(name: Notification.Name.EvaluateReconnect, object: nil) - } else { - viewController.evaluateReconnect(sender: viewController.view) - } - } + UserDefaults.shared.set(false, forKey: UserDefaults.Key.isCustomDNS) + NotificationCenter.default.post(name: Notification.Name.CustomDNSUpdated, object: nil) + self.evaluateReconnect(sender: self.view) } } From e95f590e43ebad3118ffc2ea2419f43fe31c9b1e Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 4 Sep 2024 14:35:53 +0200 Subject: [PATCH 7/8] feat(shortcuts): update AppDelegate.swift --- IVPNClient/AppDelegate.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/IVPNClient/AppDelegate.swift b/IVPNClient/AppDelegate.swift index 1753b0197..f93d4a8c7 100644 --- a/IVPNClient/AppDelegate.swift +++ b/IVPNClient/AppDelegate.swift @@ -439,3 +439,12 @@ extension AppDelegate: PurchaseManagerDelegate { } } + +enum UserActivityType { + static let Connect = "net.ivpn.clients.ios.Connect" + static let Disconnect = "net.ivpn.clients.ios.Disconnect" + static let AntiTrackerEnable = "net.ivpn.clients.ios.AntiTracker.enable" + static let AntiTrackerDisable = "net.ivpn.clients.ios.AntiTracker.disable" + static let CustomDNSEnable = "net.ivpn.clients.ios.CustomDNS.enable" + static let CustomDNSDisable = "net.ivpn.clients.ios.CustomDNS.disable" +} From c1363c49fe3185695beb36a2ae813e68abfafba6 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Sat, 7 Sep 2024 10:13:39 +0200 Subject: [PATCH 8/8] feat(shortcuts): update AppIntentsHandler.swift --- .../Scenes/MainScreen/AppIntentsHandler.swift | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift index 9e25095ab..be2e035ee 100644 --- a/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift +++ b/IVPNClient/Scenes/MainScreen/AppIntentsHandler.swift @@ -13,23 +13,11 @@ extension MainViewController { // MARK: - App Intents - @objc func intentConnect() { - DispatchQueue.delay(0.75) { - if UserDefaults.shared.networkProtectionEnabled { - Application.shared.connectionManager.resetRulesAndConnectShortcut(closeApp: true, actionType: .connect) - return - } - Application.shared.connectionManager.connect() - } + Application.shared.connectionManager.resetRulesAndConnect() } @objc func intentDisconnect() { - DispatchQueue.delay(0.75) { - if UserDefaults.shared.networkProtectionEnabled { - Application.shared.connectionManager.resetRulesAndDisconnectShortcut(closeApp: true, actionType: .disconnect) - return - } - Application.shared.connectionManager.disconnect() - } + Application.shared.connectionManager.resetRulesAndDisconnect() } @objc func intentAntiTrackerEnable() {