diff --git a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift index 3b414dd..3116f7a 100644 --- a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift +++ b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift @@ -11,7 +11,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var mainVC: MainViewController? func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let window = UIWindow(frame: UIScreen.main.bounds) window.backgroundColor = UIColor.white @@ -36,3 +36,38 @@ class AppDelegate: UIResponder, UIApplicationDelegate { mainVC?.refreshTunnelConnectionStatuses() } } + +// MARK: State restoration + +extension AppDelegate { + func application(_ application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool { + return true + } + + func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool { + return true + } + + func application(_ application: UIApplication, + viewControllerWithRestorationIdentifierPath identifierComponents: [String], + coder: NSCoder) -> UIViewController? { + guard let vcIdentifier = identifierComponents.last else { return nil } + if (vcIdentifier == "MainVC") { + return MainViewController() + } else if (vcIdentifier == "TunnelsListVC") { + return TunnelsListTableViewController() + } else if (vcIdentifier.hasPrefix("TunnelDetailVC:")) { + let tunnelName = String(vcIdentifier.suffix(vcIdentifier.count - "TunnelDetailVC:".count)) + if let tunnelsManager = mainVC?.tunnelsManager { + if let tunnel = tunnelsManager.tunnel(named: tunnelName) { + return TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel) + } + } else { + // Show it when tunnelsManager is available + mainVC?.showTunnelDetailForTunnel(named: tunnelName, animated: false) + } + + } + return nil + } +} diff --git a/WireGuard/WireGuard/UI/iOS/MainViewController.swift b/WireGuard/WireGuard/UI/iOS/MainViewController.swift index 74ad1ca..69f40d5 100644 --- a/WireGuard/WireGuard/UI/iOS/MainViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/MainViewController.swift @@ -23,6 +23,11 @@ class MainViewController: UISplitViewController { super.init(nibName: nil, bundle: nil) self.viewControllers = [ masterNC, detailNC ] + + // State restoration + self.restorationIdentifier = "MainVC" + masterNC.restorationIdentifier = "MasterNC" + detailNC.restorationIdentifier = "DetailNC" } required init?(coder aDecoder: NSCoder) { @@ -67,6 +72,30 @@ extension MainViewController { tunnelsManager.refreshStatuses() } } + + func showTunnelDetailForTunnel(named tunnelName: String, animated: Bool) { + let showTunnelDetailBlock: (TunnelsManager) -> Void = { [weak self] (tunnelsManager) in + if let tunnel = tunnelsManager.tunnel(named: tunnelName) { + let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel) + let tunnelDetailNC = UINavigationController(rootViewController: tunnelDetailVC) + tunnelDetailNC.restorationIdentifier = "DetailNC" + if let self = self { + if (animated) { + self.showDetailViewController(tunnelDetailNC, sender: self) + } else { + UIView.performWithoutAnimation { + self.showDetailViewController(tunnelDetailNC, sender: self) + } + } + } + } + } + if let tunnelsManager = tunnelsManager { + showTunnelDetailBlock(tunnelsManager) + } else { + onTunnelsManagerReady = showTunnelDetailBlock + } + } } extension MainViewController: UISplitViewControllerDelegate { diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift index 99d751b..b59c7b5 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift @@ -43,6 +43,9 @@ class TunnelDetailTableViewController: UITableViewController { self.tableView.register(TunnelDetailTableViewKeyValueCell.self, forCellReuseIdentifier: TunnelDetailTableViewKeyValueCell.id) self.tableView.register(TunnelDetailTableViewButtonCell.self, forCellReuseIdentifier: TunnelDetailTableViewButtonCell.id) self.tableView.register(TunnelDetailTableViewActivateOnDemandCell.self, forCellReuseIdentifier: TunnelDetailTableViewActivateOnDemandCell.id) + + // State restoration + self.restorationIdentifier = "TunnelDetailVC:\(tunnel.name)" } @objc func editTapped() { diff --git a/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift index f558de4..6449dbe 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift @@ -37,6 +37,9 @@ class TunnelsListTableViewController: UIViewController { ]) busyIndicator.startAnimating() self.busyIndicator = busyIndicator + + // State restoration + self.restorationIdentifier = "TunnelsListVC" } func setTunnelsManager(tunnelsManager: TunnelsManager) { @@ -266,6 +269,7 @@ extension TunnelsListTableViewController: UITableViewDelegate { let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel) let tunnelDetailNC = UINavigationController(rootViewController: tunnelDetailVC) + tunnelDetailNC.restorationIdentifier = "DetailNC" showDetailViewController(tunnelDetailNC, sender: self) // Shall get propagated up to the split-vc } diff --git a/WireGuard/WireGuard/VPN/TunnelsManager.swift b/WireGuard/WireGuard/VPN/TunnelsManager.swift index 4aada0c..4653b4c 100644 --- a/WireGuard/WireGuard/VPN/TunnelsManager.swift +++ b/WireGuard/WireGuard/VPN/TunnelsManager.swift @@ -238,6 +238,10 @@ class TunnelsManager { return tunnels[index] } + func tunnel(named tunnelName: String) -> TunnelContainer? { + return self.tunnels.first(where: { $0.name == tunnelName }) + } + func startActivation(of tunnel: TunnelContainer, completionHandler: @escaping (TunnelsManagerError?) -> Void) { guard (tunnel.status == .inactive) else { return