diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-12-05 11:10:48 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-12-05 11:10:48 +0100 |
| commit | 4e7baa1f1a194877a6cfcf9d193cd54f83be202b (patch) | |
| tree | a39de241a3324436cb692474b9663da5ad754b25 | |
| parent | 423fdbcf086aa076a260c49682268e369cc0b08e (diff) | |
| parent | f14081c8afe513df060293d3362c10eaf8ab349a (diff) | |
| download | mullvadvpn-4e7baa1f1a194877a6cfcf9d193cd54f83be202b.tar.xz mullvadvpn-4e7baa1f1a194877a6cfcf9d193cd54f83be202b.zip | |
Merge branch 'drop-intents-support'
| -rw-r--r-- | ios/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 24 | ||||
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme | 2 | ||||
| -rw-r--r-- | ios/MullvadVPN/AppDelegate.swift | 14 | ||||
| -rw-r--r-- | ios/MullvadVPN/Info.plist | 14 | ||||
| -rw-r--r-- | ios/MullvadVPN/IntentHandlers.swift | 89 | ||||
| -rw-r--r-- | ios/MullvadVPN/Intents.intentdefinition | 163 | ||||
| -rw-r--r-- | ios/MullvadVPN/SceneDelegate.swift | 2 | ||||
| -rw-r--r-- | ios/MullvadVPN/SettingsDataSource.swift | 20 | ||||
| -rw-r--r-- | ios/MullvadVPN/SettingsNavigationController.swift | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/SettingsViewController.swift | 2 | ||||
| -rw-r--r-- | ios/MullvadVPN/ShortcutsDataSource.swift | 234 | ||||
| -rw-r--r-- | ios/MullvadVPN/ShortcutsDataSourceDelegate.swift | 14 | ||||
| -rw-r--r-- | ios/MullvadVPN/ShortcutsManager.swift | 64 | ||||
| -rw-r--r-- | ios/MullvadVPN/ShortcutsViewController.swift | 116 |
15 files changed, 3 insertions, 762 deletions
diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md index 0cb7b673df..e8751c1985 100644 --- a/ios/CHANGELOG.md +++ b/ios/CHANGELOG.md @@ -30,9 +30,6 @@ Line wrap the file at 100 chars. Th - Add revoked device view displayed when the app detects that device is no longer registered on backend. - Add ability to manage registered devices if too many devices detected during log-in. -- Add intents: start VPN, stop VPN, reconnect VPN (acts as start VPN when the tunnel is down, - otherwise picks new relay). -- Add menu item to control shortcuts. - Add continuous monitoring of tunnel connection. Verify ping replies to detect whether traffic is really flowing. - Check if device is revoked or account has expired when the tunnel fails to connect on each second diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 042c517930..244617b56f 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -163,8 +163,6 @@ 5871167F2910035700D41AAC /* PreferencesInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5871167E2910035700D41AAC /* PreferencesInteractor.swift */; }; 5871FB96254ADE4E0051A0A4 /* ConsolidatedApplicationLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5871FB95254ADE4E0051A0A4 /* ConsolidatedApplicationLog.swift */; }; 5871FBA0254C26C00051A0A4 /* NSRegularExpression+IPAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5871FB9F254C26BF0051A0A4 /* NSRegularExpression+IPAddress.swift */; }; - 5872631B283F6EAB00E14ADF /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 5872631A283F6EAB00E14ADF /* Intents.intentdefinition */; }; - 5872631D283F755900E14ADF /* IntentHandlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5872631C283F755900E14ADF /* IntentHandlers.swift */; }; 58727283265D173C00F315B2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 58727282265D173C00F315B2 /* LaunchScreen.storyboard */; }; 5872D6E8286304DE00DB5F4E /* TermsOfService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5872D6E7286304DE00DB5F4E /* TermsOfService.swift */; }; 587425C12299833500CA2045 /* RootContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587425C02299833500CA2045 /* RootContainerViewController.swift */; }; @@ -323,10 +321,6 @@ 58FEEB46260A028D00A621A8 /* GeoJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FEEB45260A028D00A621A8 /* GeoJSON.swift */; }; 58FEEB58260B662E00A621A8 /* AutomaticKeyboardResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FEEB57260B662E00A621A8 /* AutomaticKeyboardResponder.swift */; }; 58FF2C03281BDE02009EF542 /* SettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF2C02281BDE02009EF542 /* SettingsManager.swift */; }; - 753D6C0C28B4BF3E0052D9E1 /* ShortcutsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753D6C0B28B4BF3E0052D9E1 /* ShortcutsManager.swift */; }; - 75FD0C2128B108570021E33E /* ShortcutsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75FD0C2028B108570021E33E /* ShortcutsDataSource.swift */; }; - 75FD0C2328B109860021E33E /* ShortcutsDataSourceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75FD0C2228B109860021E33E /* ShortcutsDataSourceDelegate.swift */; }; - 75FD0C2528B117D30021E33E /* ShortcutsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75FD0C2428B117D30021E33E /* ShortcutsViewController.swift */; }; E1187ABC289BBB850024E748 /* OutOfTimeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1187ABA289BBB850024E748 /* OutOfTimeViewController.swift */; }; E1187ABD289BBB850024E748 /* OutOfTimeContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1187ABB289BBB850024E748 /* OutOfTimeContentView.swift */; }; E158B360285381C60002F069 /* StringFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E158B35F285381C60002F069 /* StringFormatter.swift */; }; @@ -672,8 +666,6 @@ 5871167E2910035700D41AAC /* PreferencesInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesInteractor.swift; sourceTree = "<group>"; }; 5871FB95254ADE4E0051A0A4 /* ConsolidatedApplicationLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsolidatedApplicationLog.swift; sourceTree = "<group>"; }; 5871FB9F254C26BF0051A0A4 /* NSRegularExpression+IPAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+IPAddress.swift"; sourceTree = "<group>"; }; - 5872631A283F6EAB00E14ADF /* Intents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = "<group>"; }; - 5872631C283F755900E14ADF /* IntentHandlers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandlers.swift; sourceTree = "<group>"; }; 58727282265D173C00F315B2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; }; 5872D6E7286304DE00DB5F4E /* TermsOfService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfService.swift; sourceTree = "<group>"; }; 587425C02299833500CA2045 /* RootContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootContainerViewController.swift; sourceTree = "<group>"; }; @@ -826,10 +818,6 @@ 58FEEB45260A028D00A621A8 /* GeoJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoJSON.swift; sourceTree = "<group>"; }; 58FEEB57260B662E00A621A8 /* AutomaticKeyboardResponder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomaticKeyboardResponder.swift; sourceTree = "<group>"; }; 58FF2C02281BDE02009EF542 /* SettingsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsManager.swift; sourceTree = "<group>"; }; - 753D6C0B28B4BF3E0052D9E1 /* ShortcutsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsManager.swift; sourceTree = "<group>"; }; - 75FD0C2028B108570021E33E /* ShortcutsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsDataSource.swift; sourceTree = "<group>"; }; - 75FD0C2228B109860021E33E /* ShortcutsDataSourceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsDataSourceDelegate.swift; sourceTree = "<group>"; }; - 75FD0C2428B117D30021E33E /* ShortcutsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsViewController.swift; sourceTree = "<group>"; }; E1187ABA289BBB850024E748 /* OutOfTimeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutOfTimeViewController.swift; sourceTree = "<group>"; }; E1187ABB289BBB850024E748 /* OutOfTimeContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutOfTimeContentView.swift; sourceTree = "<group>"; }; E158B35F285381C60002F069 /* StringFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringFormatter.swift; sourceTree = "<group>"; }; @@ -1332,8 +1320,6 @@ 58F3C0A3249CB069003E76BE /* HeaderBarView.swift */, 58FD5BF32428C67600112C88 /* InAppPurchaseButton.swift */, 58CE5E6F224146210008646E /* Info.plist */, - 5872631C283F755900E14ADF /* IntentHandlers.swift */, - 5872631A283F6EAB00E14ADF /* Intents.intentdefinition */, 58727282265D173C00F315B2 /* LaunchScreen.storyboard */, 58E20770274672CA00DE5D77 /* LaunchViewController.swift */, 583DA21325FA4B5C00318683 /* LocationDataSource.swift */, @@ -1388,10 +1374,6 @@ 58ACF64A26553C3F00ACE4B7 /* SettingsSwitchCell.swift */, 58CCA01122424D11004F3011 /* SettingsViewController.swift */, 58677711290976FB006F721F /* SettingsInteractor.swift */, - 75FD0C2028B108570021E33E /* ShortcutsDataSource.swift */, - 75FD0C2228B109860021E33E /* ShortcutsDataSourceDelegate.swift */, - 753D6C0B28B4BF3E0052D9E1 /* ShortcutsManager.swift */, - 75FD0C2428B117D30021E33E /* ShortcutsViewController.swift */, 58BA693023EADA6A009DC256 /* SimulatorTunnelProvider.swift */, 587A01FB23F1F0BE00B68763 /* SimulatorTunnelProviderHost.swift */, 58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */, @@ -2192,7 +2174,6 @@ 588527B2276B3F0700BAA373 /* LoadTunnelConfigurationOperation.swift in Sources */, 58F1311527E0B2AB007AC5BC /* Result+Extensions.swift in Sources */, 5867770E29096984006F721F /* OutOfTimeInteractor.swift in Sources */, - 5872631B283F6EAB00E14ADF /* Intents.intentdefinition in Sources */, 58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */, 5878A27129091CF20096FC88 /* AccountInteractor.swift in Sources */, 068CE5742927B7A400A068BB /* Migration.swift in Sources */, @@ -2222,7 +2203,6 @@ 5878A279290954790096FC88 /* ConnectInteractor.swift in Sources */, 582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */, 5820EDAB288FF0D2006BF4E4 /* DeviceRowView.swift in Sources */, - 75FD0C2128B108570021E33E /* ShortcutsDataSource.swift in Sources */, 5846227726E22A7C0035F7C2 /* StorePaymentManagerDelegate.swift in Sources */, 58EF581125D69DB400AEBA94 /* StatusImageView.swift in Sources */, 58907D9524D17B4E00CFC3F5 /* DisconnectSplitButton.swift in Sources */, @@ -2240,7 +2220,6 @@ E1187ABD289BBB850024E748 /* OutOfTimeContentView.swift in Sources */, 58CC40EF24A601900019D96E /* ObserverList.swift in Sources */, 58CCA01822426713004F3011 /* AccountViewController.swift in Sources */, - 75FD0C2528B117D30021E33E /* ShortcutsViewController.swift in Sources */, 5871FBA0254C26C00051A0A4 /* NSRegularExpression+IPAddress.swift in Sources */, 58F7CA882692E34000FC59FD /* WireguardKeysContentView.swift in Sources */, 5878A27729093A4F0096FC88 /* StorePaymentBlockObserver.swift in Sources */, @@ -2276,7 +2255,6 @@ 586A950D290125F0007BAF2B /* PresentAlertOperation.swift in Sources */, 58B93A1326C3F13600A55733 /* TunnelState.swift in Sources */, 58FEEB46260A028D00A621A8 /* GeoJSON.swift in Sources */, - 753D6C0C28B4BF3E0052D9E1 /* ShortcutsManager.swift in Sources */, 58CE5E64224146200008646E /* AppDelegate.swift in Sources */, 5878A27329091D6D0096FC88 /* TunnelBlockObserver.swift in Sources */, 5872D6E8286304DE00DB5F4E /* TermsOfService.swift in Sources */, @@ -2288,7 +2266,6 @@ 06410E04292D0F7100AFC18C /* SettingsParser.swift in Sources */, 5878A27D2909657C0096FC88 /* RevokedDeviceInteractor.swift in Sources */, 58677710290975E9006F721F /* SettingsInteractorFactory.swift in Sources */, - 5872631D283F755900E14ADF /* IntentHandlers.swift in Sources */, 58CCA01222424D11004F3011 /* SettingsViewController.swift in Sources */, 06410DFE292CE18F00AFC18C /* KeychainSettingsStore.swift in Sources */, 580F8B8628197958002E0998 /* DNSSettings.swift in Sources */, @@ -2298,7 +2275,6 @@ 58293FAE2510CA58005D0BB5 /* ProblemReportViewController.swift in Sources */, 58B9EB152489139B00095626 /* DisplayChainedError.swift in Sources */, 587B753F2668E5A700DEF7E9 /* NotificationContainerView.swift in Sources */, - 75FD0C2328B109860021E33E /* ShortcutsDataSourceDelegate.swift in Sources */, 58421034282E4B1500F24E46 /* TunnelSettingsV2+REST.swift in Sources */, 58F2E144276A13F300A79513 /* StartTunnelOperation.swift in Sources */, 5868BD33261DCD2600E6027F /* CustomSplitViewController.swift in Sources */, diff --git a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme index dc70ad4ec7..c0ec326af9 100644 --- a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme +++ b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme @@ -88,7 +88,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - launchStyle = "0" + launchStyle = "1" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 1721f80261..27515a798e 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -7,7 +7,6 @@ // import BackgroundTasks -import Intents import MullvadLogging import MullvadREST import Operations @@ -156,19 +155,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD return true } - func application(_ application: UIApplication, handlerFor intent: INIntent) -> Any? { - switch intent { - case is StartVPNIntent: - return StartVPNIntentHandler(tunnelManager: tunnelManager) - case is StopVPNIntent: - return StopVPNIntentHandler(tunnelManager: tunnelManager) - case is ReconnectVPNIntent: - return ReconnectVPNIntentHandler(tunnelManager: tunnelManager) - default: - return nil - } - } - // MARK: - UISceneSession lifecycle func application( diff --git a/ios/MullvadVPN/Info.plist b/ios/MullvadVPN/Info.plist index 7fb1defbcf..9c9b1744e4 100644 --- a/ios/MullvadVPN/Info.plist +++ b/ios/MullvadVPN/Info.plist @@ -28,18 +28,6 @@ <string>$(MARKETING_VERSION)</string> <key>CFBundleVersion</key> <string>$(CURRENT_PROJECT_VERSION)</string> - <key>INIntentsRestrictedWhileLocked</key> - <array> - <string>StartVPNIntent</string> - <string>StopVPNIntent</string> - <string>ReconnectVPNIntent</string> - </array> - <key>INIntentsSupported</key> - <array> - <string>StartVPNIntent</string> - <string>StopVPNIntent</string> - <string>ReconnectVPNIntent</string> - </array> <key>ITSAppUsesNonExemptEncryption</key> <false/> <key>LSRequiresIPhoneOS</key> @@ -53,7 +41,7 @@ <key>UIApplicationSceneManifest</key> <dict> <key>UIApplicationSupportsMultipleScenes</key> - <true/> + <false/> </dict> <key>UIBackgroundModes</key> <array> diff --git a/ios/MullvadVPN/IntentHandlers.swift b/ios/MullvadVPN/IntentHandlers.swift deleted file mode 100644 index 434f09b8fe..0000000000 --- a/ios/MullvadVPN/IntentHandlers.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// IntentHandlers.swift -// MullvadVPN -// -// Created by pronebird on 26/05/2022. -// Copyright © 2022 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -final class StartVPNIntentHandler: NSObject, StartVPNIntentHandling { - private let tunnelManager: TunnelManager - - init(tunnelManager: TunnelManager) { - self.tunnelManager = tunnelManager - } - - func handle(intent: StartVPNIntent, completion: @escaping (StartVPNIntentResponse) -> Void) { - tunnelManager.startTunnel { operationCompletion in - let code: StartVPNIntentResponseCode = operationCompletion.isSuccess - ? .success - : .failure - let response = StartVPNIntentResponse(code: code, userActivity: nil) - - completion(response) - } - } -} - -final class StopVPNIntentHandler: NSObject, StopVPNIntentHandling { - private let tunnelManager: TunnelManager - - init(tunnelManager: TunnelManager) { - self.tunnelManager = tunnelManager - } - - func handle(intent: StopVPNIntent, completion: @escaping (StopVPNIntentResponse) -> Void) { - tunnelManager.stopTunnel { operationCompletion in - let code: StopVPNIntentResponseCode = operationCompletion.isSuccess - ? .success - : .failure - let response = StopVPNIntentResponse(code: code, userActivity: nil) - - completion(response) - } - } -} - -final class ReconnectVPNIntentHandler: NSObject, ReconnectVPNIntentHandling { - private let tunnelManager: TunnelManager - - init(tunnelManager: TunnelManager) { - self.tunnelManager = tunnelManager - } - - func handle( - intent: ReconnectVPNIntent, - completion: @escaping (ReconnectVPNIntentResponse) -> Void - ) { - tunnelManager.reconnectTunnel(selectNewRelay: true) { operationCompletion in - let error = operationCompletion.error - - let shouldStartTunnel: Bool - if case .tunnelDown = error as? SendTunnelProviderMessageError { - shouldStartTunnel = true - } else { - shouldStartTunnel = error is UnsetTunnelError - } - - if shouldStartTunnel { - self.tunnelManager.startTunnel { operationCompletion in - completion( - ReconnectVPNIntentResponse( - code: operationCompletion.isSuccess ? .success : .failure, - userActivity: nil - ) - ) - } - } else { - completion( - ReconnectVPNIntentResponse( - code: operationCompletion.isSuccess ? .success : .failure, - userActivity: nil - ) - ) - } - } - } -} diff --git a/ios/MullvadVPN/Intents.intentdefinition b/ios/MullvadVPN/Intents.intentdefinition deleted file mode 100644 index c05dda03cc..0000000000 --- a/ios/MullvadVPN/Intents.intentdefinition +++ /dev/null @@ -1,163 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>INEnums</key> - <array/> - <key>INIntentDefinitionModelVersion</key> - <string>1.2</string> - <key>INIntentDefinitionNamespace</key> - <string>5pIysl</string> - <key>INIntentDefinitionSystemVersion</key> - <string>21F79</string> - <key>INIntentDefinitionToolsBuildVersion</key> - <string>13F100</string> - <key>INIntentDefinitionToolsVersion</key> - <string>13.4.1</string> - <key>INIntents</key> - <array> - <dict> - <key>INIntentCategory</key> - <string>generic</string> - <key>INIntentConfigurable</key> - <true/> - <key>INIntentDescriptionID</key> - <string>jBv2Ko</string> - <key>INIntentIneligibleForSuggestions</key> - <true/> - <key>INIntentManagedParameterCombinations</key> - <dict> - <key></key> - <dict> - <key>INIntentParameterCombinationSupportsBackgroundExecution</key> - <true/> - <key>INIntentParameterCombinationUpdatesLinked</key> - <true/> - </dict> - </dict> - <key>INIntentName</key> - <string>StartVPN</string> - <key>INIntentResponse</key> - <dict> - <key>INIntentResponseCodes</key> - <array> - <dict> - <key>INIntentResponseCodeName</key> - <string>success</string> - <key>INIntentResponseCodeSuccess</key> - <true/> - </dict> - <dict> - <key>INIntentResponseCodeName</key> - <string>failure</string> - </dict> - </array> - <key>INIntentResponseLastParameterTag</key> - <integer>1</integer> - </dict> - <key>INIntentTitle</key> - <string>Start VPN</string> - <key>INIntentTitleID</key> - <string>EpurV0</string> - <key>INIntentType</key> - <string>Custom</string> - <key>INIntentVerb</key> - <string>Do</string> - </dict> - <dict> - <key>INIntentCategory</key> - <string>generic</string> - <key>INIntentConfigurable</key> - <true/> - <key>INIntentDescriptionID</key> - <string>uwGwEw</string> - <key>INIntentIneligibleForSuggestions</key> - <true/> - <key>INIntentManagedParameterCombinations</key> - <dict> - <key></key> - <dict> - <key>INIntentParameterCombinationSupportsBackgroundExecution</key> - <true/> - <key>INIntentParameterCombinationUpdatesLinked</key> - <true/> - </dict> - </dict> - <key>INIntentName</key> - <string>StopVPN</string> - <key>INIntentResponse</key> - <dict> - <key>INIntentResponseCodes</key> - <array> - <dict> - <key>INIntentResponseCodeName</key> - <string>success</string> - <key>INIntentResponseCodeSuccess</key> - <true/> - </dict> - <dict> - <key>INIntentResponseCodeName</key> - <string>failure</string> - </dict> - </array> - </dict> - <key>INIntentTitle</key> - <string>Stop VPN</string> - <key>INIntentTitleID</key> - <string>4GnhAo</string> - <key>INIntentType</key> - <string>Custom</string> - <key>INIntentVerb</key> - <string>Do</string> - </dict> - <dict> - <key>INIntentCategory</key> - <string>generic</string> - <key>INIntentConfigurable</key> - <true/> - <key>INIntentDescriptionID</key> - <string>SPC7AD</string> - <key>INIntentIneligibleForSuggestions</key> - <true/> - <key>INIntentManagedParameterCombinations</key> - <dict> - <key></key> - <dict> - <key>INIntentParameterCombinationSupportsBackgroundExecution</key> - <true/> - <key>INIntentParameterCombinationUpdatesLinked</key> - <true/> - </dict> - </dict> - <key>INIntentName</key> - <string>ReconnectVPN</string> - <key>INIntentResponse</key> - <dict> - <key>INIntentResponseCodes</key> - <array> - <dict> - <key>INIntentResponseCodeName</key> - <string>success</string> - <key>INIntentResponseCodeSuccess</key> - <true/> - </dict> - <dict> - <key>INIntentResponseCodeName</key> - <string>failure</string> - </dict> - </array> - </dict> - <key>INIntentTitle</key> - <string>Reconnect VPN</string> - <key>INIntentTitleID</key> - <string>puJvsb</string> - <key>INIntentType</key> - <string>Custom</string> - <key>INIntentVerb</key> - <string>Do</string> - </dict> - </array> - <key>INTypes</key> - <array/> -</dict> -</plist> diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift index 03f6bc3674..b022aa2772 100644 --- a/ios/MullvadVPN/SceneDelegate.swift +++ b/ios/MullvadVPN/SceneDelegate.swift @@ -155,8 +155,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe ) } - ShortcutsManager.shared.updateVoiceShortcuts() - setShowsPrivacyOverlay(false) } diff --git a/ios/MullvadVPN/SettingsDataSource.swift b/ios/MullvadVPN/SettingsDataSource.swift index ed4bf23c3d..e2510baf20 100644 --- a/ios/MullvadVPN/SettingsDataSource.swift +++ b/ios/MullvadVPN/SettingsDataSource.swift @@ -43,7 +43,6 @@ final class SettingsDataSource: NSObject, UITableViewDataSource, UITableViewDele enum Item: String { case account case preferences - case shortcuts case version case problemReport case faq @@ -98,7 +97,7 @@ final class SettingsDataSource: NSObject, UITableViewDataSource, UITableViewDele if interactor.deviceState.isLoggedIn { newSnapshot.appendSections([.main]) - newSnapshot.appendItems([.account, .preferences, .shortcuts], in: .main) + newSnapshot.appendItems([.account, .preferences], in: .main) } newSnapshot.appendSections([.version, .problemReport]) @@ -158,23 +157,6 @@ final class SettingsDataSource: NSObject, UITableViewDataSource, UITableViewDele return cell - case .shortcuts: - let cell = tableView.dequeueReusableCell( - withIdentifier: CellReuseIdentifiers.basicCell.rawValue, - for: indexPath - ) as! SettingsCell - cell.titleLabel.text = NSLocalizedString( - "SHORTCUTS_CELL_LABEL", - tableName: "Settings", - value: "Shortcuts", - comment: "" - ) - cell.detailTitleLabel.text = nil - cell.accessibilityIdentifier = nil - cell.disclosureType = .chevron - - return cell - case .version: let cell = tableView.dequeueReusableCell( withIdentifier: CellReuseIdentifiers.basicCell.rawValue, diff --git a/ios/MullvadVPN/SettingsNavigationController.swift b/ios/MullvadVPN/SettingsNavigationController.swift index 6656eb2acb..c43da954cc 100644 --- a/ios/MullvadVPN/SettingsNavigationController.swift +++ b/ios/MullvadVPN/SettingsNavigationController.swift @@ -12,7 +12,6 @@ enum SettingsNavigationRoute { case root case account case preferences - case shortcuts case problemReport } @@ -123,9 +122,6 @@ class SettingsNavigationController: CustomNavigationController, SettingsViewCont interactor: interactorFactory.makePreferencesInteractor() ) - case .shortcuts: - return ShortcutsViewController() - case .problemReport: return ProblemReportViewController( interactor: interactorFactory.makeProblemReportInteractor() diff --git a/ios/MullvadVPN/SettingsViewController.swift b/ios/MullvadVPN/SettingsViewController.swift index 3f5ce245df..2dd09d4d20 100644 --- a/ios/MullvadVPN/SettingsViewController.swift +++ b/ios/MullvadVPN/SettingsViewController.swift @@ -104,8 +104,6 @@ extension SettingsDataSource.Item { return .account case .preferences: return .preferences - case .shortcuts: - return .shortcuts case .version: return nil case .problemReport: diff --git a/ios/MullvadVPN/ShortcutsDataSource.swift b/ios/MullvadVPN/ShortcutsDataSource.swift deleted file mode 100644 index 429d196246..0000000000 --- a/ios/MullvadVPN/ShortcutsDataSource.swift +++ /dev/null @@ -1,234 +0,0 @@ -// -// ShortcutsDataSource.swift -// MullvadVPN -// -// Created by Nikolay Davydov on 20.08.2022. -// Copyright © 2022 Mullvad VPN AB. All rights reserved. -// - -import IntentsUI -import UIKit - -final class ShortcutsDataSource: NSObject, - UITableViewDataSource, - UITableViewDelegate, - ShortcutsManagerDelegate -{ - private enum CellReuseIdentifiers: String, CaseIterable { - case basicCell - - var reusableViewClass: AnyClass { - switch self { - case .basicCell: - return SettingsCell.self - } - } - } - - private enum HeaderFooterReuseIdentifier: String, CaseIterable { - case spacer - - var reusableViewClass: AnyClass { - switch self { - case .spacer: - return EmptyTableViewHeaderFooterView.self - } - } - } - - enum Section: String { - case shortcuts - } - - struct Item: Hashable { - let title: String - let shortcut: INShortcut - let voiceShortcut: INVoiceShortcut? - - var isAdded: Bool { - return voiceShortcut != nil - } - } - - private var snapshot = DataSourceSnapshot<Section, Item>() - - weak var delegate: ShortcutsDataSourceDelegate? - - weak var tableView: UITableView? { - didSet { - tableView?.delegate = self - tableView?.dataSource = self - - registerClasses() - } - } - - override init() { - super.init() - updateDataSnapshot(voiceShortcuts: []) - ShortcutsManager.shared.delegate = self - ShortcutsManager.shared.updateVoiceShortcuts() - } - - private func registerClasses() { - CellReuseIdentifiers.allCases.forEach { cellIdentifier in - tableView?.register( - cellIdentifier.reusableViewClass, - forCellReuseIdentifier: cellIdentifier.rawValue - ) - } - - HeaderFooterReuseIdentifier.allCases.forEach { reuseIdentifier in - tableView?.register( - reuseIdentifier.reusableViewClass, - forHeaderFooterViewReuseIdentifier: reuseIdentifier.rawValue - ) - } - } - - private func updateDataSnapshot(voiceShortcuts: [INVoiceShortcut]) { - var items = [Item]() - - for data in ShortcutData.allCases { - guard let shortcut = data.shortcut else { continue } - let voiceShortcut = voiceShortcuts.first(where: { voiceShortcut in - isVoiceShortcut(voiceShortcut, invokes: shortcut) - }) - let item = Item( - title: data.title, - shortcut: shortcut, - voiceShortcut: voiceShortcut - ) - items.append(item) - } - - var newSnapshot = DataSourceSnapshot<Section, Item>() - newSnapshot.appendSections([.shortcuts]) - newSnapshot.appendItems(items, in: .shortcuts) - - snapshot = newSnapshot - } - - /// Returns whether the voice shortcut performs the same action as the specified shortcut. - private func isVoiceShortcut( - _ voiceShortcut: INVoiceShortcut, - invokes shortcut: INShortcut - ) -> Bool { - if let a = voiceShortcut.shortcut.intent, let b = shortcut.intent { - return type(of: a) == type(of: b) - } - return false - } - - // MARK: - UITableViewDataSource - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - let sectionIdentifier = snapshot.section(at: section)! - return snapshot.numberOfItems(in: sectionIdentifier) ?? 0 - } - - func numberOfSections(in tableView: UITableView) -> Int { - return snapshot.numberOfSections() - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let item = snapshot.itemForIndexPath(indexPath)! - let cell = tableView.dequeueReusableCell( - withIdentifier: CellReuseIdentifiers.basicCell.rawValue, - for: indexPath - ) - if let cell = cell as? SettingsCell { - cell.titleLabel.text = item.title - cell.disclosureType = item.isAdded ? .tick : .none - } - return cell - } - - // MARK: - UITableViewDelegate - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard let item = snapshot.itemForIndexPath(indexPath) else { return } - delegate?.shortcutsDataSource(self, didSelectItem: item) - tableView.deselectRow(at: indexPath, animated: true) - } - - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - return tableView.dequeueReusableHeaderFooterView( - withIdentifier: HeaderFooterReuseIdentifier.spacer.rawValue - ) - } - - func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { - return nil - } - - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return UIMetrics.sectionSpacing - } - - func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { - return 0 - } - - // MARK: - ShortcutsManagerDelegate - - func shortcutsManager( - _ shortcutsManager: ShortcutsManager, - didReceiveVoiceShortcuts voiceShortcuts: [INVoiceShortcut] - ) { - updateDataSnapshot(voiceShortcuts: voiceShortcuts) - tableView?.reloadData() - } -} - -private extension ShortcutsDataSource { - enum ShortcutData: CaseIterable { - case start - case reconnect - case stop - - var title: String { - switch self { - case .start: - return NSLocalizedString( - "SHORTCUTS_NAME_START_VPN", - tableName: "Shortcuts", - value: "Start VPN", - comment: "" - ) - case .reconnect: - return NSLocalizedString( - "SHORTCUTS_NAME_RECONNECT_VPN", - tableName: "Shortcuts", - value: "Reconnect VPN", - comment: "" - ) - case .stop: - return NSLocalizedString( - "SHORTCUTS_NAME_STOP_VPN", - tableName: "Shortcuts", - value: "Stop VPN", - comment: "" - ) - } - } - - var shortcut: INShortcut? { - let intent: INIntent - switch self { - case .start: - intent = StartVPNIntent() - case .reconnect: - intent = ReconnectVPNIntent() - case .stop: - intent = StopVPNIntent() - } - intent.suggestedInvocationPhrase = title - guard let shortcut = INShortcut(intent: intent) else { - assertionFailure("The shortcut has an invalid intent.") - return nil - } - return shortcut - } - } -} diff --git a/ios/MullvadVPN/ShortcutsDataSourceDelegate.swift b/ios/MullvadVPN/ShortcutsDataSourceDelegate.swift deleted file mode 100644 index 2fde666721..0000000000 --- a/ios/MullvadVPN/ShortcutsDataSourceDelegate.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// ShortcutsDataSourceDelegate.swift -// MullvadVPN -// -// Created by Nikolay Davydov on 20.08.2022. -// Copyright © 2022 Mullvad VPN AB. All rights reserved. -// - -protocol ShortcutsDataSourceDelegate: AnyObject { - func shortcutsDataSource( - _ dataSource: ShortcutsDataSource, - didSelectItem item: ShortcutsDataSource.Item - ) -} diff --git a/ios/MullvadVPN/ShortcutsManager.swift b/ios/MullvadVPN/ShortcutsManager.swift deleted file mode 100644 index a991c38c65..0000000000 --- a/ios/MullvadVPN/ShortcutsManager.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// ShortcutsManager.swift -// MullvadVPN -// -// Created by Nikolay Davydov on 23.08.2022. -// Copyright © 2022 Mullvad VPN AB. All rights reserved. -// - -import IntentsUI -import MullvadLogging - -protocol ShortcutsManagerDelegate: AnyObject { - func shortcutsManager( - _ shortcutsManager: ShortcutsManager, - didReceiveVoiceShortcuts voiceShortcuts: [INVoiceShortcut] - ) -} - -final class ShortcutsManager { - static let shared = ShortcutsManager() - - private init() {} - - private let logger = Logger(label: "ShortcutsManager") - - private var voiceShortcutsByID = [UUID: INVoiceShortcut]() { - didSet { - let voiceShortcuts = voiceShortcutsByID.map { $0.value } - delegate?.shortcutsManager(self, didReceiveVoiceShortcuts: voiceShortcuts) - } - } - - weak var delegate: ShortcutsManagerDelegate? - - func updateVoiceShortcuts() { - guard delegate != nil else { return } - INVoiceShortcutCenter.shared.getAllVoiceShortcuts { [weak self] voiceShortcuts, error in - guard let self = self else { return } - if let error = error { - self.logger.error( - error: error, - message: "Failed to fetch voice shortcuts." - ) - return - } - let voiceShortcuts = voiceShortcuts ?? [] - let voiceShortcutsByID = voiceShortcuts - .reduce(into: [UUID: INVoiceShortcut]()) { result, voiceShortcut in - result[voiceShortcut.identifier] = voiceShortcut - } - DispatchQueue.main.async { - self.voiceShortcutsByID = voiceShortcutsByID - } - } - } - - func addVoiceShortcut(_ voiceShortcut: INVoiceShortcut) { - voiceShortcutsByID[voiceShortcut.identifier] = voiceShortcut - } - - func deleteVoiceShortcut(withIdentifier identifier: UUID) { - voiceShortcutsByID[identifier] = nil - } -} diff --git a/ios/MullvadVPN/ShortcutsViewController.swift b/ios/MullvadVPN/ShortcutsViewController.swift deleted file mode 100644 index 953639dca3..0000000000 --- a/ios/MullvadVPN/ShortcutsViewController.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// ShortcutsViewController.swift -// MullvadVPN -// -// Created by Nikolay Davydov on 20.08.2022. -// Copyright © 2022 Mullvad VPN AB. All rights reserved. -// - -import IntentsUI -import UIKit - -final class ShortcutsViewController: UITableViewController, - ShortcutsDataSourceDelegate, - INUIAddVoiceShortcutViewControllerDelegate, - INUIEditVoiceShortcutViewControllerDelegate -{ - private let dataSource = ShortcutsDataSource() - - override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent - } - - init() { - super.init(style: .grouped) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.backgroundColor = .secondaryColor - tableView.separatorColor = .secondaryColor - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 60 - - dataSource.tableView = tableView - dataSource.delegate = self - - navigationItem.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "Shortcuts", - value: "Shortcuts", - comment: "" - ) - } - - // MARK: - ShortcutsDataSourceDelegate - - func shortcutsDataSource( - _ dataSource: ShortcutsDataSource, - didSelectItem item: ShortcutsDataSource.Item - ) { - let controller: UIViewController - if let voiceShortcut = item.voiceShortcut { - let editShortcutController = INUIEditVoiceShortcutViewController( - voiceShortcut: voiceShortcut - ) - editShortcutController.delegate = self - controller = editShortcutController - } else { - let addShortcutController = INUIAddVoiceShortcutViewController( - shortcut: item.shortcut - ) - addShortcutController.delegate = self - controller = addShortcutController - } - controller.modalPresentationStyle = .formSheet - present(controller, animated: true) - } - - // MARK: - INUIAddVoiceShortcutViewControllerDelegate - - func addVoiceShortcutViewController( - _ controller: INUIAddVoiceShortcutViewController, - didFinishWith voiceShortcut: INVoiceShortcut?, - error: Error? - ) { - if let voiceShortcut = voiceShortcut { - ShortcutsManager.shared.addVoiceShortcut(voiceShortcut) - } - controller.dismiss(animated: true) - } - - func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) { - controller.dismiss(animated: true) - } - - // MARK: - INUIEditVoiceShortcutViewControllerDelegate - - func editVoiceShortcutViewController( - _ controller: INUIEditVoiceShortcutViewController, - didUpdate voiceShortcut: INVoiceShortcut?, - error: Error? - ) { - controller.dismiss(animated: true) - } - - func editVoiceShortcutViewController( - _ controller: INUIEditVoiceShortcutViewController, - didDeleteVoiceShortcutWithIdentifier deletedVoiceShortcutIdentifier: UUID - ) { - ShortcutsManager.shared.deleteVoiceShortcut( - withIdentifier: deletedVoiceShortcutIdentifier - ) - controller.dismiss(animated: true) - } - - func editVoiceShortcutViewControllerDidCancel( - _ controller: INUIEditVoiceShortcutViewController - ) { - controller.dismiss(animated: true) - } -} |
