import UIKit
class MainViewController: UISplitViewController {
+
+ var tunnelsManager: TunnelsManager?
+ var onTunnelsManagerReady: ((TunnelsManager) -> Void)?
+
var tunnelsListVC: TunnelsListTableViewController?
init() {
// On iPad, always show both masterVC and detailVC, even in portrait mode, like the Settings app
self.preferredDisplayMode = .allVisible
+
+ // Create the tunnels manager, and when it's ready, inform tunnelsListVC
+ TunnelsManager.create { [weak self] tunnelsManager in
+ guard let tunnelsManager = tunnelsManager else { return }
+ guard let s = self else { return }
+
+ s.tunnelsManager = tunnelsManager
+ s.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager)
+
+ tunnelsManager.activationDelegate = s
+
+ s.onTunnelsManagerReady?(tunnelsManager)
+ s.onTunnelsManagerReady = nil
+ }
+ }
+}
+
+extension MainViewController: TunnelsManagerActivationDelegate {
+ func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelActivationError) {
+ ErrorPresenter.showErrorAlert(error: error, from: self)
+ }
+}
+
+extension MainViewController {
+ func refreshTunnelConnectionStatuses() {
+ if let tunnelsManager = tunnelsManager {
+ tunnelsManager.refreshStatuses()
+ } else {
+ onTunnelsManagerReady = { tunnelsManager in
+ tunnelsManager.refreshStatuses()
+ }
+ }
}
}
class TunnelsListTableViewController: UIViewController {
var tunnelsManager: TunnelsManager?
- var onTunnelsManagerReady: ((TunnelsManager) -> Void)?
var busyIndicator: UIActivityIndicatorView?
var centeredAddButton: BorderedTextButton?
])
busyIndicator.startAnimating()
self.busyIndicator = busyIndicator
+ }
- // Create the tunnels manager, and when it's ready, create the tableView
- TunnelsManager.create { [weak self] tunnelsManager in
- guard let tunnelsManager = tunnelsManager else { return }
- guard let s = self else { return }
-
- let tableView = UITableView(frame: CGRect.zero, style: .plain)
- tableView.rowHeight = 60
- tableView.separatorStyle = .none
- tableView.register(TunnelsListTableViewCell.self, forCellReuseIdentifier: TunnelsListTableViewCell.id)
-
- s.view.addSubview(tableView)
- tableView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- tableView.leftAnchor.constraint(equalTo: s.view.leftAnchor),
- tableView.rightAnchor.constraint(equalTo: s.view.rightAnchor),
- tableView.topAnchor.constraint(equalTo: s.view.topAnchor),
- tableView.bottomAnchor.constraint(equalTo: s.view.bottomAnchor)
- ])
- tableView.dataSource = s
- tableView.delegate = s
- s.tableView = tableView
-
- // Add an add button, centered
- let centeredAddButton = BorderedTextButton()
- centeredAddButton.title = "Add a tunnel"
- centeredAddButton.isHidden = true
- s.view.addSubview(centeredAddButton)
- centeredAddButton.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- centeredAddButton.centerXAnchor.constraint(equalTo: s.view.centerXAnchor),
- centeredAddButton.centerYAnchor.constraint(equalTo: s.view.centerYAnchor)
- ])
- centeredAddButton.onTapped = { [weak self] in
- self?.addButtonTapped(sender: centeredAddButton)
- }
- s.centeredAddButton = centeredAddButton
+ func setTunnelsManager(tunnelsManager: TunnelsManager) {
+ if (self.tunnelsManager != nil) {
+ // If a tunnels manager is already set, do nothing
+ return
+ }
+
+ // Create the table view
+
+ let tableView = UITableView(frame: CGRect.zero, style: .plain)
+ tableView.rowHeight = 60
+ tableView.separatorStyle = .none
+ tableView.register(TunnelsListTableViewCell.self, forCellReuseIdentifier: TunnelsListTableViewCell.id)
- centeredAddButton.isHidden = (tunnelsManager.numberOfTunnels() > 0)
- busyIndicator.stopAnimating()
+ self.view.addSubview(tableView)
+ tableView.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ tableView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
+ tableView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
+ tableView.topAnchor.constraint(equalTo: self.view.topAnchor),
+ tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
+ ])
+ tableView.dataSource = self
+ tableView.delegate = self
+ self.tableView = tableView
+
+ // Add button at the center
- tunnelsManager.delegate = s
- tunnelsManager.activationDelegate = s
- s.tunnelsManager = tunnelsManager
- s.onTunnelsManagerReady?(tunnelsManager)
- s.onTunnelsManagerReady = nil
+ let centeredAddButton = BorderedTextButton()
+ centeredAddButton.title = "Add a tunnel"
+ centeredAddButton.isHidden = true
+ self.view.addSubview(centeredAddButton)
+ centeredAddButton.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ centeredAddButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
+ centeredAddButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
+ ])
+ centeredAddButton.onTapped = { [weak self] in
+ self?.addButtonTapped(sender: centeredAddButton)
}
+ centeredAddButton.isHidden = (tunnelsManager.numberOfTunnels() > 0)
+ self.centeredAddButton = centeredAddButton
+
+ // Hide the busy indicator
+
+ self.busyIndicator?.stopAnimating()
+
+ // Keep track of the tunnels manager
+
+ self.tunnelsManager = tunnelsManager
+ tunnelsManager.tunnelsListDelegate = self
}
@objc func addButtonTapped(sender: AnyObject) {
}
}
}
-
- func refreshTunnelConnectionStatuses() {
- if let tunnelsManager = tunnelsManager {
- tunnelsManager.refreshStatuses()
- } else {
- onTunnelsManagerReady = { tunnelsManager in
- tunnelsManager.refreshStatuses()
- }
- }
- }
}
// MARK: UIDocumentPickerDelegate
// MARK: TunnelsManagerDelegate
-extension TunnelsListTableViewController: TunnelsManagerDelegate {
+extension TunnelsListTableViewController: TunnelsManagerListDelegate {
func tunnelAdded(at index: Int) {
tableView?.insertRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
centeredAddButton?.isHidden = (tunnelsManager?.numberOfTunnels() ?? 0 > 0)
}
}
-// MARK: TunnelActivationDelegate
-
-extension TunnelsListTableViewController: TunnelActivationDelegate {
- func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelActivationError) {
- ErrorPresenter.showErrorAlert(error: error, from: self)
- }
-}
-
class TunnelsListTableViewCell: UITableViewCell {
static let id: String = "TunnelsListTableViewCell"
var tunnel: TunnelContainer? {
import NetworkExtension
import os.log
-protocol TunnelsManagerDelegate: class {
+protocol TunnelsManagerListDelegate: class {
func tunnelAdded(at: Int)
func tunnelModified(at: Int)
func tunnelMoved(at oldIndex: Int, to newIndex: Int)
func tunnelRemoved(at: Int)
}
-protocol TunnelActivationDelegate: class {
+protocol TunnelsManagerActivationDelegate: class {
func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelActivationError)
}
class TunnelsManager {
private var tunnels: [TunnelContainer]
- weak var delegate: TunnelsManagerDelegate?
- weak var activationDelegate: TunnelActivationDelegate?
+ weak var tunnelsListDelegate: TunnelsManagerListDelegate?
+ weak var activationDelegate: TunnelsManagerActivationDelegate?
private var isAddingTunnel: Bool = false
private var isModifyingTunnel: Bool = false
let tunnel = TunnelContainer(tunnel: tunnelProviderManager)
s.tunnels.append(tunnel)
s.tunnels.sort { $0.name < $1.name }
- s.delegate?.tunnelAdded(at: s.tunnels.firstIndex(of: tunnel)!)
+ s.tunnelsListDelegate?.tunnelAdded(at: s.tunnels.firstIndex(of: tunnel)!)
completionHandler(tunnel, nil)
}
}
let oldIndex = s.tunnels.firstIndex(of: tunnel)!
s.tunnels.sort { $0.name < $1.name }
let newIndex = s.tunnels.firstIndex(of: tunnel)!
- s.delegate?.tunnelMoved(at: oldIndex, to: newIndex)
+ s.tunnelsListDelegate?.tunnelMoved(at: oldIndex, to: newIndex)
}
- s.delegate?.tunnelModified(at: s.tunnels.firstIndex(of: tunnel)!)
+ s.tunnelsListDelegate?.tunnelModified(at: s.tunnels.firstIndex(of: tunnel)!)
if (tunnel.status == .active || tunnel.status == .activating || tunnel.status == .reasserting) {
// Turn off the tunnel, and then turn it back on, so the changes are made effective
if let s = self {
let index = s.tunnels.firstIndex(of: tunnel)!
s.tunnels.remove(at: index)
- s.delegate?.tunnelRemoved(at: index)
+ s.tunnelsListDelegate?.tunnelRemoved(at: index)
}
completionHandler(nil)
}