]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
macOS: Tunnel detail: Make the Activate button part of the list view
authorRoopesh Chander <roop@roopc.net>
Sun, 17 Mar 2019 11:08:07 +0000 (16:38 +0530)
committerJason A. Donenfeld <Jason@zx2c4.com>
Mon, 18 Mar 2019 05:46:55 +0000 (06:46 +0100)
Signed-off-by: Roopesh Chander <roop@roopc.net>
WireGuard/WireGuard.xcodeproj/project.pbxproj
WireGuard/WireGuard/UI/TunnelViewModel.swift
WireGuard/WireGuard/UI/macOS/View/ButtonRow.swift [new file with mode: 0644]
WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift

index a2e9730bba8b7702d241aca7d35fc0dc4d8d0dc7..5a76107d53dc23b8c1e2e58d67ffa3c0f6dc0273 100644 (file)
@@ -55,6 +55,7 @@
                6F5A2B4821AFF49A0081EDD8 /* FileManager+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */; };
                6F5D0C1D218352EF000F85AD /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C1C218352EF000F85AD /* PacketTunnelProvider.swift */; };
                6F5D0C22218352EF000F85AD /* WireGuardNetworkExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6F5D0C1A218352EF000F85AD /* WireGuardNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+               6F5EA59B223E58A8002B380A /* ButtonRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5EA59A223E58A8002B380A /* ButtonRow.swift */; };
                6F613D9B21DE33B8004B217A /* KeyValueRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F613D9A21DE33B8004B217A /* KeyValueRow.swift */; };
                6F61F1E921B932F700483816 /* WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1E821B932F700483816 /* WireGuardAppError.swift */; };
                6F61F1EB21B937EF00483816 /* WireGuardResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1EA21B937EF00483816 /* WireGuardResult.swift */; };
                6F5D0C1F218352EF000F85AD /* WireGuardNetworkExtension_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuardNetworkExtension_iOS.entitlements; sourceTree = "<group>"; };
                6F5D0C3421839E37000F85AD /* WireGuardNetworkExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardNetworkExtension-Bridging-Header.h"; sourceTree = "<group>"; };
                6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelSettingsGenerator.swift; sourceTree = "<group>"; };
+               6F5EA59A223E58A8002B380A /* ButtonRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonRow.swift; sourceTree = "<group>"; };
                6F613D9A21DE33B8004B217A /* KeyValueRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyValueRow.swift; sourceTree = "<group>"; };
                6F61F1E821B932F700483816 /* WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireGuardAppError.swift; sourceTree = "<group>"; };
                6F61F1EA21B937EF00483816 /* WireGuardResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireGuardResult.swift; sourceTree = "<group>"; };
                                5F52D0BC21E3785C00283CEA /* ConfTextStorage.swift */,
                                6F9B582721E8CD4300544D02 /* PopupRow.swift */,
                                6FE3661C21F64F6B00F78C7D /* ConfTextColorTheme.swift */,
+                               6F5EA59A223E58A8002B380A /* ButtonRow.swift */,
                        );
                        path = View;
                        sourceTree = "<group>";
                                6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */,
                                6FBA103F21D6B6FF0051C35F /* TunnelImporter.swift in Sources */,
                                6F89E17A21EDEB0E00C97BB9 /* StatusItemController.swift in Sources */,
+                               6F5EA59B223E58A8002B380A /* ButtonRow.swift in Sources */,
                                6F4DD16B21DA558800690EAE /* TunnelListRow.swift in Sources */,
                                6FE3661D21F64F6B00F78C7D /* ConfTextColorTheme.swift in Sources */,
                                5F52D0BF21E3788900283CEA /* NSColor+Hex.swift in Sources */,
index 20620fc3ffea1c0716fd7439e2c31755a498f1b2..e6b00a102b662aeaf885b450d5f1d17793707ece 100644 (file)
@@ -15,6 +15,7 @@ class TunnelViewModel {
         case mtu
         case dns
         case status
+        case toggleStatus
 
         var localizedUIString: String {
             switch self {
@@ -27,6 +28,7 @@ class TunnelViewModel {
             case .mtu: return tr("tunnelInterfaceMTU")
             case .dns: return tr("tunnelInterfaceDNS")
             case .status: return tr("tunnelInterfaceStatus")
+            case .toggleStatus: return ""
             }
         }
     }
diff --git a/WireGuard/WireGuard/UI/macOS/View/ButtonRow.swift b/WireGuard/WireGuard/UI/macOS/View/ButtonRow.swift
new file mode 100644 (file)
index 0000000..4d15f5e
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
+
+import Cocoa
+
+class ButtonRow: NSView {
+    let button: NSButton = {
+        let button = NSButton()
+        button.title = ""
+        button.setButtonType(.momentaryPushIn)
+        button.bezelStyle = .rounded
+        return button
+    }()
+
+    var buttonTitle: String {
+        get { return button.title }
+        set(value) { button.title = value }
+    }
+
+    var isButtonEnabled: Bool {
+        get { return button.isEnabled }
+        set(value) { button.isEnabled = value }
+    }
+
+    var buttonToolTip: String {
+        get { return button.toolTip ?? "" }
+        set(value) { button.toolTip = value }
+    }
+
+    var onButtonClicked: (() -> Void)?
+    var observationToken: AnyObject?
+
+    override var intrinsicContentSize: NSSize {
+        return NSSize(width: NSView.noIntrinsicMetric, height: button.intrinsicContentSize.height)
+    }
+
+    init() {
+        super.init(frame: CGRect.zero)
+
+        button.target = self
+        button.action = #selector(buttonClicked)
+
+        addSubview(button)
+        button.translatesAutoresizingMaskIntoConstraints = false
+
+        NSLayoutConstraint.activate([
+            button.centerYAnchor.constraint(equalTo: self.centerYAnchor),
+            button.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 155),
+            button.widthAnchor.constraint(greaterThanOrEqualToConstant: 100)
+        ])
+    }
+
+    required init?(coder decoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    @objc func buttonClicked() {
+        onButtonClicked?()
+    }
+
+    override func prepareForReuse() {
+        buttonTitle = ""
+        buttonToolTip = ""
+        onButtonClicked = nil
+        observationToken = nil
+    }
+}
index fc747a870c6be8a143c886af16f786bd15850cd2..9d7754257dc2810acfcb7fd9f269490c5e87e9b1 100644 (file)
@@ -32,7 +32,7 @@ class TunnelDetailTableViewController: NSViewController {
 
     static let interfaceFields: [TunnelViewModel.InterfaceField] = [
         .name, .status, .publicKey, .addresses,
-        .listenPort, .mtu, .dns
+        .listenPort, .mtu, .dns, .toggleStatus
     ]
 
     static let peerFields: [TunnelViewModel.PeerField] = [
@@ -51,16 +51,6 @@ class TunnelDetailTableViewController: NSViewController {
         return tableView
     }()
 
-    let toggleStatusButton: NSButton = {
-        let button = NSButton()
-        button.title = ""
-        button.setButtonType(.momentaryPushIn)
-        button.bezelStyle = .rounded
-        button.toolTip = "Toggle status (⌘T)"
-        button.widthAnchor.constraint(greaterThanOrEqualToConstant: 100).isActive = true
-        return button
-    }()
-
     let editButton: NSButton = {
         let button = NSButton()
         button.title = tr("Edit")
@@ -114,9 +104,6 @@ class TunnelDetailTableViewController: NSViewController {
         tableView.dataSource = self
         tableView.delegate = self
 
-        toggleStatusButton.target = self
-        toggleStatusButton.action = #selector(handleToggleActiveStatusAction)
-
         editButton.target = self
         editButton.action = #selector(handleEditTunnelAction)
 
@@ -134,11 +121,9 @@ class TunnelDetailTableViewController: NSViewController {
         containerView.addLayoutGuide(bottomControlsContainer)
         containerView.addSubview(box)
         containerView.addSubview(scrollView)
-        containerView.addSubview(toggleStatusButton)
         containerView.addSubview(editButton)
         box.translatesAutoresizingMaskIntoConstraints = false
         scrollView.translatesAutoresizingMaskIntoConstraints = false
-        toggleStatusButton.translatesAutoresizingMaskIntoConstraints = false
         editButton.translatesAutoresizingMaskIntoConstraints = false
 
         NSLayoutConstraint.activate([
@@ -150,8 +135,6 @@ class TunnelDetailTableViewController: NSViewController {
             bottomControlsContainer.heightAnchor.constraint(equalToConstant: 32),
             scrollView.bottomAnchor.constraint(equalTo: bottomControlsContainer.topAnchor),
             bottomControlsContainer.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
-            toggleStatusButton.leadingAnchor.constraint(equalTo: bottomControlsContainer.leadingAnchor),
-            bottomControlsContainer.bottomAnchor.constraint(equalTo: toggleStatusButton.bottomAnchor, constant: 0),
             editButton.trailingAnchor.constraint(equalTo: bottomControlsContainer.trailingAnchor),
             bottomControlsContainer.bottomAnchor.constraint(equalTo: editButton.bottomAnchor, constant: 0)
         ])
@@ -176,7 +159,7 @@ class TunnelDetailTableViewController: NSViewController {
 
         var interfaceSection = [(isVisible: Bool, modelRow: TableViewModelRow)]()
         for field in TunnelDetailTableViewController.interfaceFields {
-            let isStatus = field == .status
+            let isStatus = field == .status || field == .toggleStatus
             let isEmpty = tunnelViewModel.interfaceData[field].isEmpty
             interfaceSection.append((isVisible: isStatus || !isEmpty, modelRow: .interfaceFieldRow(field)))
         }
@@ -204,26 +187,6 @@ class TunnelDetailTableViewController: NSViewController {
     }
 
     func updateStatus() {
-        let toggleStatusButtonText: String
-        switch tunnel.status {
-        case .waiting:
-            toggleStatusButtonText = tr("macToggleStatusButtonWaiting")
-        case .inactive:
-            toggleStatusButtonText = tr("macToggleStatusButtonActivate")
-        case .activating:
-            toggleStatusButtonText = tr("macToggleStatusButtonActivating")
-        case .active:
-            toggleStatusButtonText = tr("macToggleStatusButtonDeactivate")
-        case .deactivating:
-            toggleStatusButtonText = tr("macToggleStatusButtonDeactivating")
-        case .reasserting:
-            toggleStatusButtonText = tr("macToggleStatusButtonReasserting")
-        case .restarting:
-            toggleStatusButtonText = tr("macToggleStatusButtonRestarting")
-        }
-        toggleStatusButton.title = toggleStatusButtonText
-        let shouldBeEnabled = (tunnel.status == .active || tunnel.status == .inactive)
-        toggleStatusButton.isEnabled = shouldBeEnabled
         if tunnel.status == .active {
             startUpdatingRuntimeConfiguration()
         } else if tunnel.status == .inactive {
@@ -392,6 +355,8 @@ extension TunnelDetailTableViewController: NSTableViewDelegate {
         case .interfaceFieldRow(let field):
             if field == .status {
                 return statusCell()
+            } else if field == .toggleStatus {
+                return toggleStatusCell()
             } else {
                 let cell: KeyValueRow = tableView.dequeueReusableCell()
                 let localizedKeyString = modelRow.isTitleRow() ? modelRow.localizedSectionKeyString() : field.localizedUIString
@@ -437,6 +402,22 @@ extension TunnelDetailTableViewController: NSTableViewDelegate {
         return cell
     }
 
+    func toggleStatusCell() -> NSView {
+        let cell: ButtonRow = tableView.dequeueReusableCell()
+        cell.buttonTitle = TunnelDetailTableViewController.localizedToggleStatusActionText(forStatus: tunnel.status)
+        cell.isButtonEnabled = (tunnel.status == .active || tunnel.status == .inactive)
+        cell.buttonToolTip = "Toggle status (⌘T)"
+        cell.onButtonClicked = { [weak self] in
+            self?.handleToggleActiveStatusAction()
+        }
+        cell.observationToken = tunnel.observe(\.status) { [weak cell] tunnel, _ in
+            guard let cell = cell else { return }
+            cell.buttonTitle = TunnelDetailTableViewController.localizedToggleStatusActionText(forStatus: tunnel.status)
+            cell.isButtonEnabled = (tunnel.status == .active || tunnel.status == .inactive)
+        }
+        return cell
+    }
+
     private static func localizedStatusDescription(forStatus status: TunnelStatus) -> String {
         switch status {
         case .inactive:
@@ -467,6 +448,25 @@ extension TunnelDetailTableViewController: NSTableViewDelegate {
             return NSImage(named: NSImage.statusNoneName)
         }
     }
+
+    private static func localizedToggleStatusActionText(forStatus status: TunnelStatus) -> String {
+        switch status {
+        case .waiting:
+            return tr("macToggleStatusButtonWaiting")
+        case .inactive:
+            return tr("macToggleStatusButtonActivate")
+        case .activating:
+            return tr("macToggleStatusButtonActivating")
+        case .active:
+            return tr("macToggleStatusButtonDeactivate")
+        case .deactivating:
+            return tr("macToggleStatusButtonDeactivating")
+        case .reasserting:
+            return tr("macToggleStatusButtonReasserting")
+        case .restarting:
+            return tr("macToggleStatusButtonRestarting")
+        }
+    }
 }
 
 extension TunnelDetailTableViewController: TunnelEditViewControllerDelegate {