]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
Tunnel edit, Tunnel view model: UI for providing On-Demand activation options
authorRoopesh Chander <roop@roopc.net>
Sat, 10 Nov 2018 13:20:09 +0000 (18:50 +0530)
committerRoopesh Chander <roop@roopc.net>
Sat, 10 Nov 2018 19:48:36 +0000 (01:18 +0530)
Signed-off-by: Roopesh Chander <roop@roopc.net>
WireGuard/WireGuard/UI/TunnelViewModel.swift
WireGuard/WireGuard/UI/iOS/TunnelEditTableViewController.swift

index 94e3e6d1fe267883b99c4f6ba2cf5ec322b851e0..bfcfb156f980fc13a0b086a1f7efc40a80b05c7d 100644 (file)
@@ -372,6 +372,7 @@ class TunnelViewModel {
 
     var interfaceData: InterfaceData
     var peersData: [PeerData]
+    var activationType: ActivationType
 
     init(tunnelConfiguration: TunnelConfiguration?) {
         let interfaceData: InterfaceData = InterfaceData()
@@ -391,6 +392,20 @@ class TunnelViewModel {
         }
         self.interfaceData = interfaceData
         self.peersData = peersData
+        self.activationType = tunnelConfiguration?.activationType ?? .activateManually
+    }
+
+    func activateOnDemandOptionText(for activationType: ActivationType) -> String {
+        switch (activationType) {
+        case .activateManually:
+            return ""
+        case .useOnDemandOverWifiAndCellular:
+            return "Over wifi and cellular"
+        case .useOnDemandOverWifiOnly:
+            return "Over wifi only"
+        case .useOnDemandOverCellularOnly:
+            return "Over cellular only"
+        }
     }
 
     func appendEmptyPeer() {
@@ -442,6 +457,7 @@ class TunnelViewModel {
             }
 
             let tunnelConfiguration = TunnelConfiguration(interface: interfaceConfiguration, peers: peerConfigurations)
+            tunnelConfiguration.activationType = self.activationType
             return .saved(tunnelConfiguration)
         }
     }
index 778cbe7686358bc9e7be987c7b1a7d1093552f2f..ed3dc8354a491eeb6edf486115c500da77e4e11b 100644 (file)
@@ -26,6 +26,12 @@ class TunnelEditTableViewController: UITableViewController {
         .deletePeer
     ]
 
+    let activateOnDemandOptions: [ActivationType] = [
+        .useOnDemandOverWifiAndCellular,
+        .useOnDemandOverWifiOnly,
+        .useOnDemandOverCellularOnly
+    ]
+
     let tunnelsManager: TunnelsManager
     let tunnel: TunnelContainer?
     let tunnelViewModel: TunnelViewModel
@@ -58,12 +64,12 @@ class TunnelEditTableViewController: UITableViewController {
         self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped))
 
         self.tableView.rowHeight = 44
-        self.tableView.allowsSelection = false
 
         self.tableView.register(TunnelEditTableViewKeyValueCell.self, forCellReuseIdentifier: TunnelEditTableViewKeyValueCell.id)
         self.tableView.register(TunnelEditTableViewReadOnlyKeyValueCell.self, forCellReuseIdentifier: TunnelEditTableViewReadOnlyKeyValueCell.id)
         self.tableView.register(TunnelEditTableViewButtonCell.self, forCellReuseIdentifier: TunnelEditTableViewButtonCell.id)
         self.tableView.register(TunnelEditTableViewSwitchCell.self, forCellReuseIdentifier: TunnelEditTableViewSwitchCell.id)
+        self.tableView.register(TunnelEditTableViewSelectionListCell.self, forCellReuseIdentifier: TunnelEditTableViewSelectionListCell.id)
     }
 
     @objc func saveTapped() {
@@ -122,7 +128,7 @@ extension TunnelEditTableViewController {
         let numberOfInterfaceSections = interfaceFieldsBySection.count
         let numberOfPeerSections = tunnelViewModel.peersData.count
 
-        return numberOfInterfaceSections + numberOfPeerSections + 1
+        return numberOfInterfaceSections + numberOfPeerSections + 1 /* Add Peer */ + 1 /* On-Demand */
     }
 
     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -138,9 +144,16 @@ extension TunnelEditTableViewController {
             let peerData = tunnelViewModel.peersData[peerIndex]
             let peerFieldsToShow = peerData.shouldAllowExcludePrivateIPsControl ? peerFields : peerFields.filter { $0 != .excludePrivateIPs }
             return peerFieldsToShow.count
-        } else {
+        } else if (section < (numberOfInterfaceSections + numberOfPeerSections + 1)) {
             // Add peer
             return 1
+        } else {
+            // On-Demand Rules
+            if (tunnelViewModel.activationType == .activateManually) {
+                return 1
+            } else {
+                return 4
+            }
         }
     }
 
@@ -154,9 +167,12 @@ extension TunnelEditTableViewController {
         } else if ((numberOfPeerSections > 0) && (section < (numberOfInterfaceSections + numberOfPeerSections))) {
             // Peer
             return "Peer"
-        } else {
+        } else if (section == (numberOfInterfaceSections + numberOfPeerSections)) {
             // Add peer
             return nil
+        } else {
+            assert(section == (numberOfInterfaceSections + numberOfPeerSections + 1))
+            return "On-Demand Activation"
         }
     }
 
@@ -344,8 +360,7 @@ extension TunnelEditTableViewController {
                 }
                 return cell
             }
-        } else {
-            assert(section == (numberOfInterfaceSections + numberOfPeerSections))
+        } else if (section == (numberOfInterfaceSections + numberOfPeerSections)) {
             // Add peer
             let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewButtonCell.id, for: indexPath) as! TunnelEditTableViewButtonCell
             cell.buttonText = "Add peer"
@@ -365,6 +380,32 @@ extension TunnelEditTableViewController {
                 }, completion: nil)
             }
             return cell
+        } else {
+            assert(section == (numberOfInterfaceSections + numberOfPeerSections + 1))
+            if (row == 0) {
+                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSwitchCell.id, for: indexPath) as! TunnelEditTableViewSwitchCell
+                cell.message = "Activate on demand"
+                cell.isOn = (tunnelViewModel.activationType != .activateManually)
+                cell.onSwitchToggled = { [weak self] (isOn) in
+                    guard let s = self else { return }
+                    let indexPaths: [IndexPath] = (1 ..< 4).map { IndexPath(row: $0, section: section) }
+                    if (isOn) {
+                        s.tunnelViewModel.activationType = .useOnDemandOverWifiAndCellular
+                        s.tableView.insertRows(at: indexPaths, with: .automatic)
+                    } else {
+                        s.tunnelViewModel.activationType = .activateManually
+                        s.tableView.deleteRows(at: indexPaths, with: .automatic)
+                    }
+                }
+                return cell
+            } else {
+                assert(row < 4)
+                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSelectionListCell.id, for: indexPath) as! TunnelEditTableViewSelectionListCell
+                let option = activateOnDemandOptions[row - 1]
+                cell.message = tunnelViewModel.activateOnDemandOptionText(for: option)
+                cell.isChecked = (tunnelViewModel.activationType == option)
+                return cell
+            }
         }
     }
 
@@ -406,6 +447,41 @@ extension TunnelEditTableViewController {
     }
 }
 
+// MARK: UITableViewDelegate
+
+extension TunnelEditTableViewController {
+    override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
+        let numberOfInterfaceSections = interfaceFieldsBySection.count
+        let numberOfPeerSections = tunnelViewModel.peersData.count
+
+        let section = indexPath.section
+        let row = indexPath.row
+
+        if (section == (numberOfInterfaceSections + numberOfPeerSections + 1)) {
+            return (row > 0) ? indexPath : nil
+        } else {
+            return nil
+        }
+    }
+
+    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        let numberOfInterfaceSections = interfaceFieldsBySection.count
+        let numberOfPeerSections = tunnelViewModel.peersData.count
+
+        let section = indexPath.section
+        let row = indexPath.row
+
+        assert(section == (numberOfInterfaceSections + numberOfPeerSections + 1))
+        assert(row > 0)
+
+        let option = activateOnDemandOptions[row - 1]
+        tunnelViewModel.activationType = option
+
+        let indexPaths: [IndexPath] = (1 ..< 4).map { IndexPath(row: $0, section: section) }
+        tableView.reloadRows(at: indexPaths, with: .automatic)
+    }
+}
+
 class TunnelEditTableViewKeyValueCell: UITableViewCell {
     static let id: String = "TunnelEditTableViewKeyValueCell"
     var key: String {
@@ -665,3 +741,30 @@ class TunnelEditTableViewSwitchCell: UITableViewCell {
         isOn = false
     }
 }
+
+class TunnelEditTableViewSelectionListCell: UITableViewCell {
+    static let id: String = "TunnelEditTableViewSelectionListCell"
+    var message: String {
+        get { return textLabel?.text ?? "" }
+        set(value) { textLabel!.text = value }
+    }
+    var isChecked: Bool {
+        didSet {
+            accessoryType = isChecked ? .checkmark : .none
+        }
+    }
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        isChecked = false
+        super.init(style: .default, reuseIdentifier: reuseIdentifier)
+    }
+
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    override func prepareForReuse() {
+        super.prepareForReuse()
+        message = ""
+        isChecked = false
+    }
+}