on-demand: macOS: Support SSIDs in on demand activation
This commit is contained in:
parent
583fb3ca7d
commit
8c1c490da2
|
@ -77,6 +77,7 @@
|
||||||
6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774EE21722D97006A79B3 /* TunnelsManager.swift */; };
|
6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774EE21722D97006A79B3 /* TunnelsManager.swift */; };
|
||||||
6F7774F321774263006A79B3 /* TunnelEditTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774F221774263006A79B3 /* TunnelEditTableViewController.swift */; };
|
6F7774F321774263006A79B3 /* TunnelEditTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774F221774263006A79B3 /* TunnelEditTableViewController.swift */; };
|
||||||
6F7F7E5F21C7D74B00527607 /* TunnelErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7F7E5E21C7D74B00527607 /* TunnelErrors.swift */; };
|
6F7F7E5F21C7D74B00527607 /* TunnelErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7F7E5E21C7D74B00527607 /* TunnelErrors.swift */; };
|
||||||
|
6F86476B222FBB07006925D9 /* ControlRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F864769222FB87C006925D9 /* ControlRow.swift */; };
|
||||||
6F89E17A21EDEB0E00C97BB9 /* StatusItemController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F89E17921EDEB0E00C97BB9 /* StatusItemController.swift */; };
|
6F89E17A21EDEB0E00C97BB9 /* StatusItemController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F89E17921EDEB0E00C97BB9 /* StatusItemController.swift */; };
|
||||||
6F89E17C21F090CC00C97BB9 /* TunnelsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F89E17B21F090CC00C97BB9 /* TunnelsTracker.swift */; };
|
6F89E17C21F090CC00C97BB9 /* TunnelsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F89E17B21F090CC00C97BB9 /* TunnelsTracker.swift */; };
|
||||||
6F8F0D7122258153000E8335 /* ActivateOnDemandViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F8F0D7022258153000E8335 /* ActivateOnDemandViewModel.swift */; };
|
6F8F0D7122258153000E8335 /* ActivateOnDemandViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F8F0D7022258153000E8335 /* ActivateOnDemandViewModel.swift */; };
|
||||||
|
@ -90,6 +91,7 @@
|
||||||
6F919EDC218C65C50023B400 /* wireguard_doc_logo_320x320.png in Resources */ = {isa = PBXBuildFile; fileRef = 6F919ED8218C65C50023B400 /* wireguard_doc_logo_320x320.png */; };
|
6F919EDC218C65C50023B400 /* wireguard_doc_logo_320x320.png in Resources */ = {isa = PBXBuildFile; fileRef = 6F919ED8218C65C50023B400 /* wireguard_doc_logo_320x320.png */; };
|
||||||
6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F9B582721E8CD4300544D02 /* PopupRow.swift */; };
|
6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F9B582721E8CD4300544D02 /* PopupRow.swift */; };
|
||||||
6FB1017921C57DE600766195 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; };
|
6FB1017921C57DE600766195 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; };
|
||||||
|
6FB17946222FD5960018AE71 /* OnDemandWiFiControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB17945222FD5960018AE71 /* OnDemandWiFiControls.swift */; };
|
||||||
6FB1BD6021D2607A00A991BF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1BD5F21D2607A00A991BF /* AppDelegate.swift */; };
|
6FB1BD6021D2607A00A991BF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1BD5F21D2607A00A991BF /* AppDelegate.swift */; };
|
||||||
6FB1BD6221D2607E00A991BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FB1BD6121D2607E00A991BF /* Assets.xcassets */; };
|
6FB1BD6221D2607E00A991BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FB1BD6121D2607E00A991BF /* Assets.xcassets */; };
|
||||||
6FB1BD9921D4BFE700A991BF /* WireGuardNetworkExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6FB1BD9121D4BFE600A991BF /* WireGuardNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
6FB1BD9921D4BFE700A991BF /* WireGuardNetworkExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6FB1BD9121D4BFE600A991BF /* WireGuardNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
@ -300,6 +302,7 @@
|
||||||
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsManager.swift; sourceTree = "<group>"; };
|
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsManager.swift; sourceTree = "<group>"; };
|
||||||
6F7774F221774263006A79B3 /* TunnelEditTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelEditTableViewController.swift; sourceTree = "<group>"; };
|
6F7774F221774263006A79B3 /* TunnelEditTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelEditTableViewController.swift; sourceTree = "<group>"; };
|
||||||
6F7F7E5E21C7D74B00527607 /* TunnelErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelErrors.swift; sourceTree = "<group>"; };
|
6F7F7E5E21C7D74B00527607 /* TunnelErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelErrors.swift; sourceTree = "<group>"; };
|
||||||
|
6F864769222FB87C006925D9 /* ControlRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlRow.swift; sourceTree = "<group>"; };
|
||||||
6F89E17921EDEB0E00C97BB9 /* StatusItemController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusItemController.swift; sourceTree = "<group>"; };
|
6F89E17921EDEB0E00C97BB9 /* StatusItemController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusItemController.swift; sourceTree = "<group>"; };
|
||||||
6F89E17B21F090CC00C97BB9 /* TunnelsTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsTracker.swift; sourceTree = "<group>"; };
|
6F89E17B21F090CC00C97BB9 /* TunnelsTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsTracker.swift; sourceTree = "<group>"; };
|
||||||
6F8F0D7022258153000E8335 /* ActivateOnDemandViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandViewModel.swift; sourceTree = "<group>"; };
|
6F8F0D7022258153000E8335 /* ActivateOnDemandViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -312,6 +315,7 @@
|
||||||
6F919ED8218C65C50023B400 /* wireguard_doc_logo_320x320.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = wireguard_doc_logo_320x320.png; sourceTree = "<group>"; };
|
6F919ED8218C65C50023B400 /* wireguard_doc_logo_320x320.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = wireguard_doc_logo_320x320.png; sourceTree = "<group>"; };
|
||||||
6F9B582721E8CD4300544D02 /* PopupRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupRow.swift; sourceTree = "<group>"; };
|
6F9B582721E8CD4300544D02 /* PopupRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupRow.swift; sourceTree = "<group>"; };
|
||||||
6FB1017821C57DE600766195 /* MockTunnels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTunnels.swift; sourceTree = "<group>"; };
|
6FB1017821C57DE600766195 /* MockTunnels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTunnels.swift; sourceTree = "<group>"; };
|
||||||
|
6FB17945222FD5960018AE71 /* OnDemandWiFiControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnDemandWiFiControls.swift; sourceTree = "<group>"; };
|
||||||
6FB1BD5D21D2607A00A991BF /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
6FB1BD5D21D2607A00A991BF /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
6FB1BD5F21D2607A00A991BF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
6FB1BD5F21D2607A00A991BF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
6FB1BD6121D2607E00A991BF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
6FB1BD6121D2607E00A991BF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
@ -443,6 +447,8 @@
|
||||||
6F9B582721E8CD4300544D02 /* PopupRow.swift */,
|
6F9B582721E8CD4300544D02 /* PopupRow.swift */,
|
||||||
6FE3661C21F64F6B00F78C7D /* ConfTextColorTheme.swift */,
|
6FE3661C21F64F6B00F78C7D /* ConfTextColorTheme.swift */,
|
||||||
6F5EA59A223E58A8002B380A /* ButtonRow.swift */,
|
6F5EA59A223E58A8002B380A /* ButtonRow.swift */,
|
||||||
|
6F864769222FB87C006925D9 /* ControlRow.swift */,
|
||||||
|
6FB17945222FD5960018AE71 /* OnDemandWiFiControls.swift */,
|
||||||
);
|
);
|
||||||
path = View;
|
path = View;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1183,6 +1189,7 @@
|
||||||
6B586C55220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
|
6B586C55220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
|
||||||
6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */,
|
6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */,
|
||||||
6BAC16E6221634B300A5FB78 /* AppStorePrivacyNotice.swift in Sources */,
|
6BAC16E6221634B300A5FB78 /* AppStorePrivacyNotice.swift in Sources */,
|
||||||
|
6FB17946222FD5960018AE71 /* OnDemandWiFiControls.swift in Sources */,
|
||||||
6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */,
|
6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */,
|
||||||
6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */,
|
6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */,
|
||||||
6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */,
|
6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */,
|
||||||
|
@ -1197,6 +1204,7 @@
|
||||||
6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */,
|
6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */,
|
||||||
6FB1BDC021D50F0200A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
6FB1BDC021D50F0200A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||||
6FBA101821D656000051C35F /* StatusMenu.swift in Sources */,
|
6FBA101821D656000051C35F /* StatusMenu.swift in Sources */,
|
||||||
|
6F86476B222FBB07006925D9 /* ControlRow.swift in Sources */,
|
||||||
6F613D9B21DE33B8004B217A /* KeyValueRow.swift in Sources */,
|
6F613D9B21DE33B8004B217A /* KeyValueRow.swift in Sources */,
|
||||||
6FB1BDC121D50F0200A991BF /* String+ArrayConversion.swift in Sources */,
|
6FB1BDC121D50F0200A991BF /* String+ArrayConversion.swift in Sources */,
|
||||||
5F52D0BB21E3781B00283CEA /* ConfTextView.swift in Sources */,
|
5F52D0BB21E3781B00283CEA /* ConfTextView.swift in Sources */,
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class ControlRow: 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
|
||||||
|
}()
|
||||||
|
|
||||||
|
var key: String {
|
||||||
|
get { return keyLabel.stringValue }
|
||||||
|
set(value) { keyLabel.stringValue = value }
|
||||||
|
}
|
||||||
|
|
||||||
|
override var intrinsicContentSize: NSSize {
|
||||||
|
let height = max(keyLabel.intrinsicContentSize.height, controlView.intrinsicContentSize.height)
|
||||||
|
return NSSize(width: NSView.noIntrinsicMetric, height: height)
|
||||||
|
}
|
||||||
|
|
||||||
|
let controlView: NSView
|
||||||
|
|
||||||
|
init(controlView: NSView) {
|
||||||
|
self.controlView = controlView
|
||||||
|
super.init(frame: CGRect.zero)
|
||||||
|
|
||||||
|
addSubview(keyLabel)
|
||||||
|
addSubview(controlView)
|
||||||
|
keyLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
controlView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
keyLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor),
|
||||||
|
self.leadingAnchor.constraint(equalTo: keyLabel.leadingAnchor),
|
||||||
|
keyLabel.trailingAnchor.constraint(equalTo: controlView.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 = ""
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class OnDemandWiFiControls: NSStackView {
|
||||||
|
|
||||||
|
let onDemandWiFiCheckbox: NSButton = {
|
||||||
|
let checkbox = NSButton()
|
||||||
|
checkbox.title = tr("tunnelOnDemandWiFi")
|
||||||
|
checkbox.setButtonType(.switch)
|
||||||
|
checkbox.state = .off
|
||||||
|
return checkbox
|
||||||
|
}()
|
||||||
|
|
||||||
|
static let onDemandSSIDOptions: [ActivateOnDemandViewModel.OnDemandSSIDOption] = [
|
||||||
|
.anySSID, .onlySpecificSSIDs, .exceptSpecificSSIDs
|
||||||
|
]
|
||||||
|
|
||||||
|
let onDemandSSIDOptionsPopup = NSPopUpButton()
|
||||||
|
|
||||||
|
let onDemandSSIDsField: NSTokenField = {
|
||||||
|
let tokenField = NSTokenField()
|
||||||
|
tokenField.tokenizingCharacterSet = CharacterSet([])
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
tokenField.widthAnchor.constraint(greaterThanOrEqualToConstant: 150)
|
||||||
|
])
|
||||||
|
return tokenField
|
||||||
|
}()
|
||||||
|
|
||||||
|
override var intrinsicContentSize: NSSize {
|
||||||
|
let minHeight: CGFloat = 22
|
||||||
|
let height = max(minHeight, onDemandWiFiCheckbox.intrinsicContentSize.height, onDemandSSIDOptionsPopup.intrinsicContentSize.height, onDemandSSIDsField.intrinsicContentSize.height)
|
||||||
|
return NSSize(width: NSView.noIntrinsicMetric, height: height)
|
||||||
|
}
|
||||||
|
|
||||||
|
var onDemandViewModel: ActivateOnDemandViewModel? {
|
||||||
|
didSet { updateSSIDControls() }
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
super.init(frame: CGRect.zero)
|
||||||
|
onDemandSSIDOptionsPopup.addItems(withTitles: OnDemandWiFiControls.onDemandSSIDOptions.map { $0.localizedUIString })
|
||||||
|
setViews([onDemandWiFiCheckbox, onDemandSSIDOptionsPopup, onDemandSSIDsField], in: .leading)
|
||||||
|
orientation = .horizontal
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
onDemandWiFiCheckbox.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||||
|
onDemandSSIDOptionsPopup.lastBaselineAnchor.constraint(equalTo: onDemandWiFiCheckbox.lastBaselineAnchor),
|
||||||
|
onDemandSSIDsField.lastBaselineAnchor.constraint(equalTo: onDemandWiFiCheckbox.lastBaselineAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
onDemandWiFiCheckbox.target = self
|
||||||
|
onDemandWiFiCheckbox.action = #selector(wiFiCheckboxToggled)
|
||||||
|
|
||||||
|
onDemandSSIDOptionsPopup.target = self
|
||||||
|
onDemandSSIDOptionsPopup.action = #selector(ssidOptionsPopupValueChanged)
|
||||||
|
|
||||||
|
updateSSIDControls()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder decoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveToViewModel() {
|
||||||
|
guard let onDemandViewModel = onDemandViewModel else { return }
|
||||||
|
onDemandViewModel.isWiFiInterfaceEnabled = onDemandWiFiCheckbox.state == .on
|
||||||
|
onDemandViewModel.ssidOption = OnDemandWiFiControls.onDemandSSIDOptions[onDemandSSIDOptionsPopup.indexOfSelectedItem]
|
||||||
|
onDemandViewModel.selectedSSIDs = (onDemandSSIDsField.objectValue as? [String]) ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateSSIDControls() {
|
||||||
|
guard let onDemandViewModel = onDemandViewModel else { return }
|
||||||
|
onDemandWiFiCheckbox.state = onDemandViewModel.isWiFiInterfaceEnabled ? .on : .off
|
||||||
|
let optionIndex = OnDemandWiFiControls.onDemandSSIDOptions.firstIndex(of: onDemandViewModel.ssidOption)
|
||||||
|
onDemandSSIDOptionsPopup.selectItem(at: optionIndex ?? 0)
|
||||||
|
onDemandSSIDsField.objectValue = onDemandViewModel.selectedSSIDs
|
||||||
|
onDemandSSIDOptionsPopup.isHidden = !onDemandViewModel.isWiFiInterfaceEnabled
|
||||||
|
onDemandSSIDsField.isHidden = !onDemandViewModel.isWiFiInterfaceEnabled || onDemandViewModel.ssidOption == .anySSID
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func wiFiCheckboxToggled() {
|
||||||
|
onDemandViewModel?.isWiFiInterfaceEnabled = onDemandWiFiCheckbox.state == .on
|
||||||
|
updateSSIDControls()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func ssidOptionsPopupValueChanged() {
|
||||||
|
let selectedIndex = onDemandSSIDOptionsPopup.indexOfSelectedItem
|
||||||
|
onDemandViewModel?.ssidOption = OnDemandWiFiControls.onDemandSSIDOptions[selectedIndex]
|
||||||
|
onDemandViewModel?.selectedSSIDs = (onDemandSSIDsField.objectValue as? [String]) ?? []
|
||||||
|
updateSSIDControls()
|
||||||
|
if !onDemandSSIDsField.isHidden {
|
||||||
|
onDemandSSIDsField.becomeFirstResponder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,12 +42,16 @@ class TunnelEditViewController: NSViewController {
|
||||||
return textView
|
return textView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let onDemandRow: PopupRow = {
|
let onDemandEthernetCheckbox: NSButton = {
|
||||||
let popupRow = PopupRow()
|
let checkbox = NSButton()
|
||||||
popupRow.key = tr("macFieldOnDemand")
|
checkbox.title = tr("tunnelOnDemandEthernet")
|
||||||
return popupRow
|
checkbox.setButtonType(.switch)
|
||||||
|
checkbox.state = .off
|
||||||
|
return checkbox
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
let onDemandWiFiControls = OnDemandWiFiControls()
|
||||||
|
|
||||||
let scrollView: NSScrollView = {
|
let scrollView: NSScrollView = {
|
||||||
let scrollView = NSScrollView()
|
let scrollView = NSScrollView()
|
||||||
scrollView.hasVerticalScroller = true
|
scrollView.hasVerticalScroller = true
|
||||||
|
@ -89,6 +93,7 @@ class TunnelEditViewController: NSViewController {
|
||||||
|
|
||||||
let tunnelsManager: TunnelsManager
|
let tunnelsManager: TunnelsManager
|
||||||
let tunnel: TunnelContainer?
|
let tunnel: TunnelContainer?
|
||||||
|
var onDemandViewModel: ActivateOnDemandViewModel
|
||||||
|
|
||||||
weak var delegate: TunnelEditViewControllerDelegate?
|
weak var delegate: TunnelEditViewControllerDelegate?
|
||||||
|
|
||||||
|
@ -101,6 +106,7 @@ class TunnelEditViewController: NSViewController {
|
||||||
init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer?) {
|
init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer?) {
|
||||||
self.tunnelsManager = tunnelsManager
|
self.tunnelsManager = tunnelsManager
|
||||||
self.tunnel = tunnel
|
self.tunnel = tunnel
|
||||||
|
self.onDemandViewModel = tunnel != nil ? ActivateOnDemandViewModel(setting: tunnel!.activateOnDemandSetting) : ActivateOnDemandViewModel()
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +115,6 @@ class TunnelEditViewController: NSViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateFields() {
|
func populateFields() {
|
||||||
let selectedActivateOnDemandOption: ActivateOnDemandOption
|
|
||||||
if let tunnel = tunnel {
|
if let tunnel = tunnel {
|
||||||
// Editing an existing tunnel
|
// Editing an existing tunnel
|
||||||
let tunnelConfiguration = tunnel.tunnelConfiguration!
|
let tunnelConfiguration = tunnel.tunnelConfiguration!
|
||||||
|
@ -117,11 +122,6 @@ class TunnelEditViewController: NSViewController {
|
||||||
textView.string = tunnelConfiguration.asWgQuickConfig()
|
textView.string = tunnelConfiguration.asWgQuickConfig()
|
||||||
publicKeyRow.value = tunnelConfiguration.interface.publicKey.base64Key() ?? ""
|
publicKeyRow.value = tunnelConfiguration.interface.publicKey.base64Key() ?? ""
|
||||||
textView.privateKeyString = tunnelConfiguration.interface.privateKey.base64Key() ?? ""
|
textView.privateKeyString = tunnelConfiguration.interface.privateKey.base64Key() ?? ""
|
||||||
if tunnel.activateOnDemandSetting.isActivateOnDemandEnabled {
|
|
||||||
selectedActivateOnDemandOption = tunnel.activateOnDemandSetting.activateOnDemandOption
|
|
||||||
} else {
|
|
||||||
selectedActivateOnDemandOption = .none
|
|
||||||
}
|
|
||||||
let singlePeer = tunnelConfiguration.peers.count == 1 ? tunnelConfiguration.peers.first : nil
|
let singlePeer = tunnelConfiguration.peers.count == 1 ? tunnelConfiguration.peers.first : nil
|
||||||
updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: singlePeer?.allowedIPs.map { $0.stringRepresentation })
|
updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: singlePeer?.allowedIPs.map { $0.stringRepresentation })
|
||||||
dnsServersAddedToAllowedIPs = excludePrivateIPsCheckbox.state == .on ? tunnelConfiguration.interface.dns.map { $0.stringRepresentation }.joined(separator: ", ") : nil
|
dnsServersAddedToAllowedIPs = excludePrivateIPsCheckbox.state == .on ? tunnelConfiguration.interface.dns.map { $0.stringRepresentation }.joined(separator: ", ") : nil
|
||||||
|
@ -132,7 +132,6 @@ class TunnelEditViewController: NSViewController {
|
||||||
let bootstrappingText = "[Interface]\nPrivateKey = \(privateKey.base64Key() ?? "")\n"
|
let bootstrappingText = "[Interface]\nPrivateKey = \(privateKey.base64Key() ?? "")\n"
|
||||||
publicKeyRow.value = publicKey.base64Key() ?? ""
|
publicKeyRow.value = publicKey.base64Key() ?? ""
|
||||||
textView.string = bootstrappingText
|
textView.string = bootstrappingText
|
||||||
selectedActivateOnDemandOption = .none
|
|
||||||
}
|
}
|
||||||
privateKeyObservationToken = textView.observe(\.privateKeyString) { [weak publicKeyRow] textView, _ in
|
privateKeyObservationToken = textView.observe(\.privateKeyString) { [weak publicKeyRow] textView, _ in
|
||||||
if let privateKeyString = textView.privateKeyString,
|
if let privateKeyString = textView.privateKeyString,
|
||||||
|
@ -150,14 +149,25 @@ class TunnelEditViewController: NSViewController {
|
||||||
singlePeerAllowedIPsObservationToken = textView.observe(\.singlePeerAllowedIPs) { [weak self] textView, _ in
|
singlePeerAllowedIPsObservationToken = textView.observe(\.singlePeerAllowedIPs) { [weak self] textView, _ in
|
||||||
self?.updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: textView.singlePeerAllowedIPs)
|
self?.updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: textView.singlePeerAllowedIPs)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDemandRow.valueOptions = activateOnDemandOptions.map { TunnelViewModel.activateOnDemandOptionText(for: $0) }
|
|
||||||
onDemandRow.selectedOptionIndex = activateOnDemandOptions.firstIndex(of: selectedActivateOnDemandOption)!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func loadView() {
|
override func loadView() {
|
||||||
populateFields()
|
populateFields()
|
||||||
|
|
||||||
|
let onDemandEthernetRow = ControlRow(controlView: onDemandEthernetCheckbox)
|
||||||
|
onDemandEthernetRow.key = tr("macFieldOnDemand")
|
||||||
|
onDemandEthernetCheckbox.state = onDemandViewModel.isNonWiFiInterfaceEnabled ? .on : .off
|
||||||
|
|
||||||
|
let onDemandWiFiRow = ControlRow(controlView: onDemandWiFiControls)
|
||||||
|
onDemandWiFiRow.key = ""
|
||||||
|
onDemandWiFiControls.onDemandViewModel = onDemandViewModel
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
onDemandEthernetRow.keyLabel.firstBaselineAnchor.constraint(equalTo: onDemandEthernetRow.controlView.firstBaselineAnchor),
|
||||||
|
onDemandWiFiRow.controlView.centerYAnchor.constraint(equalTo: onDemandWiFiRow.centerYAnchor),
|
||||||
|
onDemandWiFiRow.trailingAnchor.constraint(equalTo: onDemandWiFiControls.trailingAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
scrollView.documentView = textView
|
scrollView.documentView = textView
|
||||||
|
|
||||||
saveButton.target = self
|
saveButton.target = self
|
||||||
|
@ -172,7 +182,7 @@ class TunnelEditViewController: NSViewController {
|
||||||
let margin: CGFloat = 20
|
let margin: CGFloat = 20
|
||||||
let internalSpacing: CGFloat = 10
|
let internalSpacing: CGFloat = 10
|
||||||
|
|
||||||
let editorStackView = NSStackView(views: [nameRow, publicKeyRow, onDemandRow, scrollView])
|
let editorStackView = NSStackView(views: [nameRow, publicKeyRow, onDemandEthernetRow, onDemandWiFiRow, scrollView])
|
||||||
editorStackView.orientation = .vertical
|
editorStackView.orientation = .vertical
|
||||||
editorStackView.setHuggingPriority(.defaultHigh, for: .horizontal)
|
editorStackView.setHuggingPriority(.defaultHigh, for: .horizontal)
|
||||||
editorStackView.spacing = internalSpacing
|
editorStackView.spacing = internalSpacing
|
||||||
|
@ -210,13 +220,10 @@ class TunnelEditViewController: NSViewController {
|
||||||
ErrorPresenter.showErrorAlert(title: tr("macAlertNameIsEmpty"), message: "", from: self)
|
ErrorPresenter.showErrorAlert(title: tr("macAlertNameIsEmpty"), message: "", from: self)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let onDemandSetting: ActivateOnDemandSetting
|
|
||||||
let onDemandOption = activateOnDemandOptions[onDemandRow.selectedOptionIndex]
|
onDemandViewModel.isNonWiFiInterfaceEnabled = onDemandEthernetCheckbox.state == .on
|
||||||
if onDemandOption == .none {
|
onDemandWiFiControls.saveToViewModel()
|
||||||
onDemandSetting = ActivateOnDemandSetting.defaultSetting
|
let onDemandSetting = ActivateOnDemandSetting(with: onDemandViewModel.toOnDemandOption())
|
||||||
} else {
|
|
||||||
onDemandSetting = ActivateOnDemandSetting(isActivateOnDemandEnabled: true, activateOnDemandOption: onDemandOption)
|
|
||||||
}
|
|
||||||
|
|
||||||
let isTunnelModifiedWithoutChangingName = (tunnel != nil && tunnel!.name == name)
|
let isTunnelModifiedWithoutChangingName = (tunnel != nil && tunnel!.name == name)
|
||||||
guard isTunnelModifiedWithoutChangingName || tunnelsManager.tunnel(named: name) == nil else {
|
guard isTunnelModifiedWithoutChangingName || tunnelsManager.tunnel(named: name) == nil else {
|
||||||
|
|
Loading…
Reference in New Issue