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") }