aboutsummaryrefslogtreecommitdiffstats
path: root/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift
diff options
context:
space:
mode:
authorRoopesh Chander <roop@roopc.net>2018-10-26 15:56:44 +0530
committerRoopesh Chander <roop@roopc.net>2018-10-27 19:07:16 +0530
commit10c40852391f74c64a75246705352ba8bfa17ee6 (patch)
treeb926b8a25b2af5d8db28547e3c788f7ef52461b4 /WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift
parentVPN: Activating, deactivating and tracking the status (diff)
downloadwireguard-apple-10c40852391f74c64a75246705352ba8bfa17ee6.tar.xz
wireguard-apple-10c40852391f74c64a75246705352ba8bfa17ee6.zip
Tunnel detail: UI for activating and deactivating a tunnel
Signed-off-by: Roopesh Chander <roop@roopc.net>
Diffstat (limited to 'WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift')
-rw-r--r--WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift159
1 files changed, 144 insertions, 15 deletions
diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift
index b44be45..f5a6936 100644
--- a/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift
+++ b/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift
@@ -39,6 +39,7 @@ class TunnelDetailTableViewController: UITableViewController {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped))
self.tableView.rowHeight = 44
+ self.tableView.register(TunnelDetailTableViewStatusCell.self, forCellReuseIdentifier: TunnelDetailTableViewStatusCell.id)
self.tableView.register(TunnelDetailTableViewKeyValueCell.self, forCellReuseIdentifier: TunnelDetailTableViewKeyValueCell.id)
self.tableView.register(TunnelDetailTableViewButtonCell.self, forCellReuseIdentifier: TunnelDetailTableViewButtonCell.id)
}
@@ -50,6 +51,14 @@ class TunnelDetailTableViewController: UITableViewController {
editNC.modalPresentationStyle = .formSheet
present(editNC, animated: true)
}
+
+ func showErrorAlert(title: String, message: String) {
+ let okAction = UIAlertAction(title: "Ok", style: .default)
+ let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
+ alert.addAction(okAction)
+
+ self.present(alert, animated: true, completion: nil)
+ }
}
// MARK: TunnelEditTableViewControllerDelegate
@@ -75,7 +84,7 @@ extension TunnelDetailTableViewController {
let numberOfPeerSections = peerFieldsBySection.count
let numberOfPeers = tunnelViewModel.peersData.count
- return numberOfInterfaceSections + (numberOfPeers * numberOfPeerSections) + 1
+ return 1 + numberOfInterfaceSections + (numberOfPeers * numberOfPeerSections) + 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -86,10 +95,13 @@ extension TunnelDetailTableViewController {
let numberOfPeerSections = peerFieldsBySection.count
let numberOfPeers = tunnelViewModel.peersData.count
- if (section < numberOfInterfaceSections) {
+ if (section == 0) {
+ // Status
+ return 1
+ } else if (section < (1 + numberOfInterfaceSections)) {
// Interface
- return interfaceData.filterFieldsWithValueOrControl(interfaceFields: interfaceFieldsBySection[section]).count
- } else if ((numberOfPeers > 0) && (section < (numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))) {
+ return interfaceData.filterFieldsWithValueOrControl(interfaceFields: interfaceFieldsBySection[section - 1]).count
+ } else if ((numberOfPeers > 0) && (section < (1 + numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))) {
// Peer
let peerIndex = Int((section - numberOfInterfaceSections) / numberOfPeerSections)
let peerData = tunnelViewModel.peersData[peerIndex]
@@ -109,13 +121,16 @@ extension TunnelDetailTableViewController {
let numberOfPeerSections = peerFieldsBySection.count
let numberOfPeers = tunnelViewModel.peersData.count
- if (section < numberOfInterfaceSections) {
+ if (section == 0) {
+ // Status
+ return "Status"
+ } else if (section < 1 + numberOfInterfaceSections) {
// Interface
- return (section == 0) ? "Interface" : nil
- } else if ((numberOfPeers > 0) && (section < (numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))) {
+ return (section == 1) ? "Interface" : nil
+ } else if ((numberOfPeers > 0) && (section < (1 + numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))) {
// Peer
- let fieldIndex = (section - numberOfInterfaceSections) % numberOfPeerSections
- return (fieldIndex == 0) ? "Peer" : nil
+ let peerSectionIndex = (section - 1 - numberOfInterfaceSections) % numberOfPeerSections
+ return (peerSectionIndex == 0) ? "Peer" : nil
} else {
// Add peer
return nil
@@ -133,9 +148,41 @@ extension TunnelDetailTableViewController {
let section = indexPath.section
let row = indexPath.row
- if (section < numberOfInterfaceSections) {
+ if (section == 0) {
+ // Status
+ let cell = tableView.dequeueReusableCell(withIdentifier: TunnelDetailTableViewStatusCell.id, for: indexPath) as! TunnelDetailTableViewStatusCell
+ cell.tunnel = self.tunnel
+ cell.onSwitchToggled = { [weak self] isOn in
+ cell.isSwitchInteractionEnabled = false
+ guard let s = self else { return }
+ if (isOn) {
+ s.tunnelsManager.activate(tunnel: s.tunnel) { [weak s] isActivated in
+ if (!isActivated) {
+ DispatchQueue.main.async {
+ cell.setSwitchStatus(isOn: false)
+ }
+ s?.showErrorAlert(title: "Could not activate",
+ message: "Could not activate the tunnel because of an internal error")
+ }
+ cell.isSwitchInteractionEnabled = true
+ }
+ } else {
+ s.tunnelsManager.deactivate(tunnel: s.tunnel) { [weak s] isDeactivated in
+ cell.isSwitchInteractionEnabled = true
+ if (!isDeactivated) {
+ DispatchQueue.main.async {
+ cell.setSwitchStatus(isOn: true)
+ }
+ s?.showErrorAlert(title: "Could not deactivate",
+ message: "Could not deactivate the tunnel because of an internal error")
+ }
+ }
+ }
+ }
+ return cell
+ } else if (section < 1 + numberOfInterfaceSections) {
// Interface
- let field = interfaceData.filterFieldsWithValueOrControl(interfaceFields: interfaceFieldsBySection[section])[row]
+ let field = interfaceData.filterFieldsWithValueOrControl(interfaceFields: interfaceFieldsBySection[section - 1])[row]
if (field == .copyPublicKey) {
let cell = tableView.dequeueReusableCell(withIdentifier: TunnelDetailTableViewButtonCell.id, for: indexPath) as! TunnelDetailTableViewButtonCell
cell.buttonText = field.rawValue
@@ -155,10 +202,10 @@ extension TunnelDetailTableViewController {
}
return cell
}
- } else if ((numberOfPeers > 0) && (section < (numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))) {
+ } else if ((numberOfPeers > 0) && (section < (1 + numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))) {
// Peer
- let peerIndex = Int((section - numberOfInterfaceSections) / numberOfPeerSections)
- let peerSectionIndex = (section - numberOfInterfaceSections) % numberOfPeerSections
+ let peerIndex = Int((section - 1 - numberOfInterfaceSections) / numberOfPeerSections)
+ let peerSectionIndex = (section - 1 - numberOfInterfaceSections) % numberOfPeerSections
let peerData = tunnelViewModel.peersData[peerIndex]
let field = peerData.filterFieldsWithValueOrControl(peerFields: peerFieldsBySection[peerSectionIndex])[row]
@@ -174,7 +221,7 @@ extension TunnelDetailTableViewController {
return cell
} else {
- assert(section == (numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))
+ assert(section == (1 + numberOfInterfaceSections + numberOfPeers * numberOfPeerSections))
// Delete configuration
let cell = tableView.dequeueReusableCell(withIdentifier: TunnelDetailTableViewButtonCell.id, for: indexPath) as! TunnelDetailTableViewButtonCell
cell.buttonText = "Delete tunnel"
@@ -186,6 +233,88 @@ extension TunnelDetailTableViewController {
}
}
+class TunnelDetailTableViewStatusCell: UITableViewCell {
+ static let id: String = "TunnelDetailTableViewStatusCell"
+
+ var tunnel: TunnelContainer? {
+ didSet(value) {
+ update(from: tunnel?.status)
+ statusObservervationToken = tunnel?.observe(\.status) { [weak self] (tunnel, _) in
+ self?.update(from: tunnel.status)
+ }
+ }
+ }
+ var isSwitchInteractionEnabled: Bool {
+ get { return statusSwitch.isUserInteractionEnabled }
+ set(value) { statusSwitch.isUserInteractionEnabled = value }
+ }
+ var onSwitchToggled: ((Bool) -> Void)? = nil
+ private var isOnSwitchToggledHandlerEnabled: Bool = true
+
+ func setSwitchStatus(isOn: Bool) {
+ statusSwitch.isOn = isOn
+ }
+
+ let statusSwitch: UISwitch
+ private var statusObservervationToken: AnyObject? = nil
+
+ override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
+ statusSwitch = UISwitch()
+ super.init(style: .default, reuseIdentifier: TunnelDetailTableViewKeyValueCell.id)
+ accessoryView = statusSwitch
+
+ statusSwitch.addTarget(self, action: #selector(switchToggled), for: .valueChanged)
+ }
+
+ @objc func switchToggled() {
+ if (isOnSwitchToggledHandlerEnabled) {
+ onSwitchToggled?(statusSwitch.isOn)
+ }
+ }
+
+ private func update(from status: TunnelStatus?) {
+ guard let status = status else {
+ reset()
+ return
+ }
+ let text: String
+ switch (status) {
+ case .inactive:
+ text = "Inactive"
+ case .activating:
+ text = "Activating"
+ case .active:
+ text = "Active"
+ case .deactivating:
+ text = "Deactivating"
+ case .reasserting:
+ text = "Reactivating"
+ case .waitingForOtherDeactivation:
+ text = "Waiting"
+ case .resolvingEndpointDomains:
+ text = "Resolving domains"
+ }
+ textLabel?.text = text
+ setSwitchStatus(isOn: !(status == .deactivating || status == .inactive))
+ textLabel?.textColor = (status == .active || status == .inactive) ? UIColor.black : UIColor.gray
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ private func reset() {
+ textLabel?.text = "Invalid"
+ statusSwitch.isOn = false
+ textLabel?.textColor = UIColor.gray
+ statusSwitch.isUserInteractionEnabled = false
+ }
+
+ override func prepareForReuse() {
+ reset()
+ }
+}
+
class TunnelDetailTableViewKeyValueCell: UITableViewCell {
static let id: String = "TunnelDetailTableViewKeyValueCell"
var key: String {