From 13e8c6b1780eab5bd7257ba79020651e421f099c Mon Sep 17 00:00:00 2001 From: Roopesh Chander Date: Wed, 9 Jan 2019 04:14:08 +0530 Subject: macOS: Support for on-demand activation Signed-off-by: Roopesh Chander --- WireGuard/WireGuard/UI/macOS/View/PopupRow.swift | 75 ++++++++++++++++++++++ .../TunnelDetailTableViewController.swift | 11 ++++ .../ViewController/TunnelEditViewController.swift | 36 ++++++++++- 3 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 WireGuard/WireGuard/UI/macOS/View/PopupRow.swift (limited to 'WireGuard/WireGuard/UI') diff --git a/WireGuard/WireGuard/UI/macOS/View/PopupRow.swift b/WireGuard/WireGuard/UI/macOS/View/PopupRow.swift new file mode 100644 index 0000000..2ef55f5 --- /dev/null +++ b/WireGuard/WireGuard/UI/macOS/View/PopupRow.swift @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018 WireGuard LLC. All Rights Reserved. + +import Cocoa + +class PopupRow: NSView { + let keyLabel: NSTextField = { + let keyLabel = NSTextField() + keyLabel.isEditable = false + keyLabel.isSelectable = false + keyLabel.isBordered = false + keyLabel.alignment = .right + keyLabel.maximumNumberOfLines = 1 + keyLabel.lineBreakMode = .byTruncatingTail + keyLabel.backgroundColor = .clear + return keyLabel + }() + + let valuePopup = NSPopUpButton() + + var key: String { + get { return keyLabel.stringValue } + set(value) { keyLabel.stringValue = value } + } + + var valueOptions: [String] { + get { return valuePopup.itemTitles } + set(value) { + valuePopup.removeAllItems() + valuePopup.addItems(withTitles: value) + } + } + + var selectedOptionIndex: Int { + get { return valuePopup.indexOfSelectedItem } + set(value) { valuePopup.selectItem(at: value) } + } + + override var intrinsicContentSize: NSSize { + let height = max(keyLabel.intrinsicContentSize.height, valuePopup.intrinsicContentSize.height) + return NSSize(width: NSView.noIntrinsicMetric, height: height) + } + + init() { + super.init(frame: CGRect.zero) + + addSubview(keyLabel) + addSubview(valuePopup) + keyLabel.translatesAutoresizingMaskIntoConstraints = false + valuePopup.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + keyLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor), + keyLabel.firstBaselineAnchor.constraint(equalTo: valuePopup.firstBaselineAnchor), + self.leadingAnchor.constraint(equalTo: keyLabel.leadingAnchor), + keyLabel.trailingAnchor.constraint(equalTo: valuePopup.leadingAnchor, constant: -5) + ]) + + keyLabel.setContentCompressionResistancePriority(.defaultHigh + 2, for: .horizontal) + keyLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) + + let widthConstraint = keyLabel.widthAnchor.constraint(equalToConstant: 150) + widthConstraint.priority = .defaultHigh + 1 + widthConstraint.isActive = true + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + key = "" + valueOptions = [] + } +} diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift index 3c07060..5f6c891 100644 --- a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift +++ b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift @@ -8,12 +8,14 @@ class TunnelDetailTableViewController: NSViewController { private enum TableViewModelRow { case interfaceFieldRow(TunnelViewModel.InterfaceField) case peerFieldRow(peer: TunnelViewModel.PeerData, field: TunnelViewModel.PeerField) + case onDemandRow case spacerRow func localizedSectionKeyString() -> String { switch self { case .interfaceFieldRow: return tr("tunnelSectionTitleInterface") case .peerFieldRow: return tr("tunnelSectionTitlePeer") + case .onDemandRow: return "" case .spacerRow: return "" } } @@ -22,6 +24,7 @@ class TunnelDetailTableViewController: NSViewController { switch self { case .interfaceFieldRow(let field): return field == .name case .peerFieldRow(_, let field): return field == .publicKey + case .onDemandRow: return true case .spacerRow: return false } } @@ -163,6 +166,8 @@ class TunnelDetailTableViewController: NSViewController { tableViewModelRows.append(.peerFieldRow(peer: peerData, field: field)) } } + tableViewModelRows.append(.spacerRow) + tableViewModelRows.append(.onDemandRow) } func updateStatus() { @@ -232,6 +237,12 @@ extension TunnelDetailTableViewController: NSTableViewDelegate { return cell case .spacerRow: return NSView() + case .onDemandRow: + let cell: KeyValueRow = tableView.dequeueReusableCell() + cell.key = tr("macFieldOnDemand") + cell.value = TunnelViewModel.activateOnDemandDetailText(for: tunnel.activateOnDemandSetting) + cell.isKeyInBold = true + return cell } } } diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift index ae95fba..aecb3c9 100644 --- a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift +++ b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift @@ -41,6 +41,12 @@ class TunnelEditViewController: NSViewController { return textView }() + let onDemandRow: PopupRow = { + let popupRow = PopupRow() + popupRow.key = tr("macFieldOnDemand") + return popupRow + }() + let scrollView: NSScrollView = { let scrollView = NSScrollView() scrollView.hasVerticalScroller = true @@ -64,6 +70,13 @@ class TunnelEditViewController: NSViewController { return button }() + let activateOnDemandOptions: [ActivateOnDemandOption] = [ + .none, + .useOnDemandOverWiFiOrEthernet, + .useOnDemandOverWiFiOnly, + .useOnDemandOverEthernetOnly + ] + let tunnelsManager: TunnelsManager let tunnel: TunnelContainer? @@ -82,6 +95,7 @@ class TunnelEditViewController: NSViewController { } func populateTextFields() { + let selectedActivateOnDemandOption: ActivateOnDemandOption if let tunnel = tunnel { // Editing an existing tunnel let tunnelConfiguration = tunnel.tunnelConfiguration! @@ -99,6 +113,11 @@ class TunnelEditViewController: NSViewController { publicKeyRow?.value = "" } } + if tunnel.activateOnDemandSetting.isActivateOnDemandEnabled { + selectedActivateOnDemandOption = tunnel.activateOnDemandSetting.activateOnDemandOption + } else { + selectedActivateOnDemandOption = .none + } } else { // Creating a new tunnel let privateKey = Curve25519.generatePrivateKey() @@ -109,7 +128,13 @@ class TunnelEditViewController: NSViewController { """ publicKeyRow.value = publicKey.base64EncodedString() textView.string = bootstrappingText + selectedActivateOnDemandOption = .none } + + onDemandRow.valueOptions = activateOnDemandOptions.map { + return TunnelViewModel.activateOnDemandOptionText(for: $0) + } + onDemandRow.selectedOptionIndex = activateOnDemandOptions.firstIndex(of: selectedActivateOnDemandOption)! } override func loadView() { @@ -126,7 +151,7 @@ class TunnelEditViewController: NSViewController { let margin: CGFloat = 20 let internalSpacing: CGFloat = 10 - let editorStackView = NSStackView(views: [nameRow, publicKeyRow, scrollView]) + let editorStackView = NSStackView(views: [nameRow, publicKeyRow, onDemandRow, scrollView]) editorStackView.orientation = .vertical editorStackView.setHuggingPriority(.defaultHigh, for: .horizontal) editorStackView.spacing = internalSpacing @@ -157,6 +182,13 @@ class TunnelEditViewController: NSViewController { ErrorPresenter.showErrorAlert(title: tr("macAlertNameIsEmpty"), message: "", from: self) return } + let onDemandSetting: ActivateOnDemandSetting + let onDemandOption = activateOnDemandOptions[onDemandRow.selectedOptionIndex] + if onDemandOption == .none { + onDemandSetting = ActivateOnDemandSetting.defaultSetting + } else { + onDemandSetting = ActivateOnDemandSetting(isActivateOnDemandEnabled: true, activateOnDemandOption: onDemandOption) + } if let tunnel = tunnel { // We're modifying an existing tunnel if name != tunnel.name && tunnelsManager.tunnel(named: name) != nil { @@ -165,7 +197,6 @@ class TunnelEditViewController: NSViewController { } do { let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: textView.string, called: nameRow.value) - let onDemandSetting = ActivateOnDemandSetting.defaultSetting tunnelsManager.modify(tunnel: tunnel, tunnelConfiguration: tunnelConfiguration, activateOnDemandSetting: onDemandSetting) { [weak self] error in if let error = error { ErrorPresenter.showErrorAlert(error: error, from: self) @@ -187,7 +218,6 @@ class TunnelEditViewController: NSViewController { } do { let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: textView.string, called: nameRow.value) - let onDemandSetting = ActivateOnDemandSetting.defaultSetting tunnelsManager.add(tunnelConfiguration: tunnelConfiguration, activateOnDemandSetting: onDemandSetting) { [weak self] result in if let error = result.error { ErrorPresenter.showErrorAlert(error: error, from: self) -- cgit v1.2.3-59-g8ed1b