aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopesh Chander <roop@roopc.net>2019-04-30 18:28:06 +0530
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-25 13:24:01 +0200
commit393718dfaf164548250898ec740475dba126a816 (patch)
treeeaa5dfb2a3bca61b5033c0dc364e084131e30453
parentiOS: Keep track of most-recently-activated tunnels (diff)
downloadwireguard-apple-393718dfaf164548250898ec740475dba126a816.tar.xz
wireguard-apple-393718dfaf164548250898ec740475dba126a816.zip
iOS: Show Home screen quick actions for recent tunnels
Signed-off-by: Roopesh Chander <roop@roopc.net>
-rw-r--r--WireGuard/WireGuard.xcodeproj/project.pbxproj4
-rw-r--r--WireGuard/WireGuard/Tunnel/TunnelsManager.swift4
-rw-r--r--WireGuard/WireGuard/UI/iOS/AppDelegate.swift26
-rw-r--r--WireGuard/WireGuard/UI/iOS/QuickActionItem.swift25
-rw-r--r--WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift13
5 files changed, 69 insertions, 3 deletions
diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj
index d499929..c107701 100644
--- a/WireGuard/WireGuard.xcodeproj/project.pbxproj
+++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj
@@ -55,6 +55,7 @@
6F2449E8226587B90047B9E9 /* MacAppStoreUpdateDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */; };
6F3E02E9228000F6001FE7E3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3E02E8228000F6001FE7E3 /* MainMenu.swift */; };
6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */; };
+ 6F29A94722787B1600DC6A6B /* QuickActionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F29A94622787B1600DC6A6B /* QuickActionItem.swift */; };
6F4DD16B21DA558800690EAE /* TunnelListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16A21DA558800690EAE /* TunnelListRow.swift */; };
6F4DD16C21DA558F00690EAE /* NSTableView+Reuse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */; };
6F4DD16E21DBEA0700690EAE /* ManageTunnelsRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16D21DBEA0700690EAE /* ManageTunnelsRootViewController.swift */; };
@@ -305,6 +306,7 @@
6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacAppStoreUpdateDetector.swift; sourceTree = "<group>"; };
6F3E02E8228000F6001FE7E3 /* MainMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentTunnelsTracker.swift; sourceTree = "<group>"; };
+ 6F29A94622787B1600DC6A6B /* QuickActionItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickActionItem.swift; sourceTree = "<group>"; };
6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTableView+Reuse.swift"; sourceTree = "<group>"; };
6F4DD16A21DA558800690EAE /* TunnelListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelListRow.swift; sourceTree = "<group>"; };
6F4DD16D21DBEA0700690EAE /* ManageTunnelsRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageTunnelsRootViewController.swift; sourceTree = "<group>"; };
@@ -571,6 +573,7 @@
6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */,
5F45417C21C1B23600994C13 /* UITableViewCell+Reuse.swift */,
6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */,
+ 6F29A94622787B1600DC6A6B /* QuickActionItem.swift */,
6FF4AC23211EC472002C96EB /* Info.plist */,
6FF4AC482120B9E0002C96EB /* WireGuard.entitlements */,
);
@@ -1358,6 +1361,7 @@
buildActionMask = 2147483647;
files = (
6FE1765A21C90E87002690EA /* LocalizationHelper.swift in Sources */,
+ 6F29A94722787B1600DC6A6B /* QuickActionItem.swift in Sources */,
6FF3527221C2616C0008484E /* ringlogger.c in Sources */,
6F0F44CB222D55FD00B0FF04 /* EditableTextCell.swift in Sources */,
6FF3527321C2616C0008484E /* Logger.swift in Sources */,
diff --git a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
index 460a9f6..2781131 100644
--- a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
+++ b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
@@ -311,6 +311,10 @@ class TunnelsManager {
return tunnels[index]
}
+ func mapTunnels<T>(transform: (TunnelContainer) throws -> T) rethrows -> [T] {
+ return try tunnels.map(transform)
+ }
+
func index(of tunnel: TunnelContainer) -> Int? {
return tunnels.firstIndex(of: tunnel)
}
diff --git a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift
index d274280..8884d44 100644
--- a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift
+++ b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift
@@ -9,10 +9,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var mainVC: MainViewController?
+ var isLaunchedForSpecificAction = false
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Logger.configureGlobal(tagged: "APP", withFilePath: FileManager.logFileURL?.path)
+ if let launchOptions = launchOptions {
+ if launchOptions[.url] != nil || launchOptions[.shortcutItem] != nil {
+ isLaunchedForSpecificAction = true
+ }
+ }
+
let window = UIWindow(frame: UIScreen.main.bounds)
window.backgroundColor = .white
self.window = window
@@ -37,6 +44,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidBecomeActive(_ application: UIApplication) {
mainVC?.refreshTunnelConnectionStatuses()
}
+
+ func applicationWillResignActive(_ application: UIApplication) {
+ guard let allTunnelNames = mainVC?.allTunnelNames() else { return }
+ application.shortcutItems = QuickActionItem.createItems(allTunnelNames: allTunnelNames)
+ }
+
+ func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
+ guard shortcutItem.type == QuickActionItem.type else {
+ completionHandler(false)
+ return
+ }
+ let tunnelName = shortcutItem.localizedTitle
+ mainVC?.showTunnelDetailForTunnel(named: tunnelName, animated: false, shouldToggleStatus: true)
+ completionHandler(true)
+ }
}
extension AppDelegate {
@@ -45,7 +67,7 @@ extension AppDelegate {
}
func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
- return true
+ return !self.isLaunchedForSpecificAction
}
func application(_ application: UIApplication, viewControllerWithRestorationIdentifierPath identifierComponents: [String], coder: NSCoder) -> UIViewController? {
@@ -58,7 +80,7 @@ extension AppDelegate {
}
} else {
// Show it when tunnelsManager is available
- mainVC?.showTunnelDetailForTunnel(named: tunnelName, animated: false)
+ mainVC?.showTunnelDetailForTunnel(named: tunnelName, animated: false, shouldToggleStatus: false)
}
}
return nil
diff --git a/WireGuard/WireGuard/UI/iOS/QuickActionItem.swift b/WireGuard/WireGuard/UI/iOS/QuickActionItem.swift
new file mode 100644
index 0000000..4367fa9
--- /dev/null
+++ b/WireGuard/WireGuard/UI/iOS/QuickActionItem.swift
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
+
+import UIKit
+
+class QuickActionItem: UIApplicationShortcutItem {
+ static let type = "WireGuardTunnelActivateAndShow"
+
+ init(tunnelName: String) {
+ super.init(type: QuickActionItem.type, localizedTitle: tunnelName, localizedSubtitle: nil, icon: nil, userInfo: nil)
+ }
+
+ static func createItems(allTunnelNames: [String]) -> [QuickActionItem] {
+ let numberOfItems = 10
+ // Currently, only 4 items shown by iOS, but that can increase in the future.
+ // iOS will discard additional items we give it.
+ var tunnelNames = RecentTunnelsTracker.recentlyActivatedTunnelNames(limit: numberOfItems)
+ let numberOfSlotsRemaining = numberOfItems - tunnelNames.count
+ if numberOfSlotsRemaining > 0 {
+ let moreTunnels = allTunnelNames.filter { !tunnelNames.contains($0) }.prefix(numberOfSlotsRemaining)
+ tunnelNames.append(contentsOf: moreTunnels)
+ }
+ return tunnelNames.map { QuickActionItem(tunnelName: $0) }
+ }
+}
diff --git a/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift b/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift
index 380299c..1929c79 100644
--- a/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift
+++ b/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift
@@ -57,6 +57,10 @@ class MainViewController: UISplitViewController {
}
}
+ func allTunnelNames() -> [String]? {
+ guard let tunnelsManager = self.tunnelsManager else { return nil }
+ return tunnelsManager.mapTunnels { $0.name }
+ }
}
extension MainViewController: TunnelsManagerActivationDelegate {
@@ -84,7 +88,7 @@ extension MainViewController {
}
}
- func showTunnelDetailForTunnel(named tunnelName: String, animated: Bool) {
+ func showTunnelDetailForTunnel(named tunnelName: String, animated: Bool, shouldToggleStatus: Bool) {
let showTunnelDetailBlock: (TunnelsManager) -> Void = { [weak self] tunnelsManager in
if let tunnel = tunnelsManager.tunnel(named: tunnelName) {
let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
@@ -99,6 +103,13 @@ extension MainViewController {
}
}
}
+ if shouldToggleStatus {
+ if tunnel.status == .inactive {
+ tunnelsManager.startActivation(of: tunnel)
+ } else if tunnel.status == .active {
+ tunnelsManager.startDeactivation(of: tunnel)
+ }
+ }
}
}
if let tunnelsManager = tunnelsManager {