summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-11-30 15:43:00 +0100
committerAndrej Mihajlov <and@mullvad.net>2022-12-05 10:55:05 +0100
commitf14081c8afe513df060293d3362c10eaf8ab349a (patch)
treea39de241a3324436cb692474b9663da5ad754b25
parentf868646830e0c9f764bc243f7ee1316b7171aac4 (diff)
downloadmullvadvpn-f14081c8afe513df060293d3362c10eaf8ab349a.tar.xz
mullvadvpn-f14081c8afe513df060293d3362c10eaf8ab349a.zip
Drop intents support
Sadly we cannot support intents since we can't run multiple copies of our main scene without synchronizing state between all of them. Not to mention we never intended this to work this way. Also, currently there is no known way to prevent user from creating multiple windows of the app on iPadOS.
-rw-r--r--ios/CHANGELOG.md3
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj24
-rw-r--r--ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme2
-rw-r--r--ios/MullvadVPN/AppDelegate.swift14
-rw-r--r--ios/MullvadVPN/Info.plist12
-rw-r--r--ios/MullvadVPN/IntentHandlers.swift89
-rw-r--r--ios/MullvadVPN/Intents.intentdefinition163
-rw-r--r--ios/MullvadVPN/SceneDelegate.swift2
-rw-r--r--ios/MullvadVPN/SettingsDataSource.swift20
-rw-r--r--ios/MullvadVPN/SettingsNavigationController.swift4
-rw-r--r--ios/MullvadVPN/SettingsViewController.swift2
-rw-r--r--ios/MullvadVPN/ShortcutsDataSource.swift234
-rw-r--r--ios/MullvadVPN/ShortcutsDataSourceDelegate.swift14
-rw-r--r--ios/MullvadVPN/ShortcutsManager.swift64
-rw-r--r--ios/MullvadVPN/ShortcutsViewController.swift116
15 files changed, 2 insertions, 761 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 687433d3a5..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>
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)
- }
-}