aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopesh Chander <roop@roopc.net>2019-03-17 16:38:07 +0530
committerJason A. Donenfeld <Jason@zx2c4.com>2019-03-18 06:46:55 +0100
commit0f98312d150bfcbcfd90267462fdaf88d8f82517 (patch)
treea767875a717a3f4b4a34ae5b780693647e7a76fc
parentmacOS: Nullify observationToken on prepareForReuse() (diff)
downloadwireguard-apple-0f98312d150bfcbcfd90267462fdaf88d8f82517.tar.xz
wireguard-apple-0f98312d150bfcbcfd90267462fdaf88d8f82517.zip
macOS: Tunnel detail: Make the Activate button part of the list view
Signed-off-by: Roopesh Chander <roop@roopc.net>
-rw-r--r--WireGuard/WireGuard.xcodeproj/project.pbxproj4
-rw-r--r--WireGuard/WireGuard/UI/TunnelViewModel.swift2
-rw-r--r--WireGuard/WireGuard/UI/macOS/View/ButtonRow.swift67
-rw-r--r--WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift78
4 files changed, 112 insertions, 39 deletions
diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj
index a2e9730b..5a76107d 100644
--- a/WireGuard/WireGuard.xcodeproj/project.pbxproj
+++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj
@@ -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 */; };
@@ -270,6 +271,7 @@
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>"; };
@@ -425,6 +427,7 @@
5F52D0BC21E3785C00283CEA /* ConfTextStorage.swift */,
6F9B582721E8CD4300544D02 /* PopupRow.swift */,
6FE3661C21F64F6B00F78C7D /* ConfTextColorTheme.swift */,
+ 6F5EA59A223E58A8002B380A /* ButtonRow.swift */,
);
path = View;
sourceTree = "<group>";
@@ -1165,6 +1168,7 @@
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 */,
diff --git a/WireGuard/WireGuard/UI/TunnelViewModel.swift b/WireGuard/WireGuard/UI/TunnelViewModel.swift
index 20620fc3..e6b00a10 100644
--- a/WireGuard/WireGuard/UI/TunnelViewModel.swift
+++ b/WireGuard/WireGuard/UI/TunnelViewModel.swift
@@ -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
index 00000000..4d15f5ee
--- /dev/null
+++ b/WireGuard/WireGuard/UI/macOS/View/ButtonRow.swift
@@ -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
+ }
+}
diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift
index fc747a87..9d775425 100644
--- a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift
+++ b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift
@@ -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 {