aboutsummaryrefslogtreecommitdiffstats
path: root/Sources/WireGuardApp/UI/macOS/ViewController/ManageTunnelsRootViewController.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Sources/WireGuardApp/UI/macOS/ViewController/ManageTunnelsRootViewController.swift')
-rw-r--r--Sources/WireGuardApp/UI/macOS/ViewController/ManageTunnelsRootViewController.swift135
1 files changed, 135 insertions, 0 deletions
diff --git a/Sources/WireGuardApp/UI/macOS/ViewController/ManageTunnelsRootViewController.swift b/Sources/WireGuardApp/UI/macOS/ViewController/ManageTunnelsRootViewController.swift
new file mode 100644
index 0000000..88eb8be
--- /dev/null
+++ b/Sources/WireGuardApp/UI/macOS/ViewController/ManageTunnelsRootViewController.swift
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
+
+import Cocoa
+
+class ManageTunnelsRootViewController: NSViewController {
+
+ let tunnelsManager: TunnelsManager
+ var tunnelsListVC: TunnelsListTableViewController?
+ var tunnelDetailVC: TunnelDetailTableViewController?
+ let tunnelDetailContainerView = NSView()
+ var tunnelDetailContentVC: NSViewController?
+
+ init(tunnelsManager: TunnelsManager) {
+ self.tunnelsManager = tunnelsManager
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func loadView() {
+ view = NSView()
+
+ let horizontalSpacing: CGFloat = 20
+ let verticalSpacing: CGFloat = 20
+ let centralSpacing: CGFloat = 10
+
+ let container = NSLayoutGuide()
+ view.addLayoutGuide(container)
+ NSLayoutConstraint.activate([
+ container.topAnchor.constraint(equalTo: view.topAnchor, constant: verticalSpacing),
+ view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: verticalSpacing),
+ container.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: horizontalSpacing),
+ view.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: horizontalSpacing)
+ ])
+
+ tunnelsListVC = TunnelsListTableViewController(tunnelsManager: tunnelsManager)
+ tunnelsListVC!.delegate = self
+ let tunnelsListView = tunnelsListVC!.view
+
+ addChild(tunnelsListVC!)
+ view.addSubview(tunnelsListView)
+ view.addSubview(tunnelDetailContainerView)
+
+ tunnelsListView.translatesAutoresizingMaskIntoConstraints = false
+ tunnelDetailContainerView.translatesAutoresizingMaskIntoConstraints = false
+
+ NSLayoutConstraint.activate([
+ tunnelsListView.topAnchor.constraint(equalTo: container.topAnchor),
+ tunnelsListView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
+ tunnelsListView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
+ tunnelDetailContainerView.topAnchor.constraint(equalTo: container.topAnchor),
+ tunnelDetailContainerView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
+ tunnelDetailContainerView.leadingAnchor.constraint(equalTo: tunnelsListView.trailingAnchor, constant: centralSpacing),
+ tunnelDetailContainerView.trailingAnchor.constraint(equalTo: container.trailingAnchor)
+ ])
+ }
+
+ private func setTunnelDetailContentVC(_ contentVC: NSViewController) {
+ if let currentContentVC = tunnelDetailContentVC {
+ currentContentVC.view.removeFromSuperview()
+ currentContentVC.removeFromParent()
+ }
+ addChild(contentVC)
+ tunnelDetailContainerView.addSubview(contentVC.view)
+ contentVC.view.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ tunnelDetailContainerView.topAnchor.constraint(equalTo: contentVC.view.topAnchor),
+ tunnelDetailContainerView.bottomAnchor.constraint(equalTo: contentVC.view.bottomAnchor),
+ tunnelDetailContainerView.leadingAnchor.constraint(equalTo: contentVC.view.leadingAnchor),
+ tunnelDetailContainerView.trailingAnchor.constraint(equalTo: contentVC.view.trailingAnchor)
+ ])
+ tunnelDetailContentVC = contentVC
+ }
+}
+
+extension ManageTunnelsRootViewController: TunnelsListTableViewControllerDelegate {
+ func tunnelsSelected(tunnelIndices: [Int]) {
+ assert(!tunnelIndices.isEmpty)
+ if tunnelIndices.count == 1 {
+ let tunnel = tunnelsManager.tunnel(at: tunnelIndices.first!)
+ if tunnel.isTunnelAvailableToUser {
+ let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
+ setTunnelDetailContentVC(tunnelDetailVC)
+ self.tunnelDetailVC = tunnelDetailVC
+ } else {
+ let unusableTunnelDetailVC = tunnelDetailContentVC as? UnusableTunnelDetailViewController ?? UnusableTunnelDetailViewController()
+ unusableTunnelDetailVC.onButtonClicked = { [weak tunnelsListVC] in
+ tunnelsListVC?.handleRemoveTunnelAction()
+ }
+ setTunnelDetailContentVC(unusableTunnelDetailVC)
+ self.tunnelDetailVC = nil
+ }
+ } else if tunnelIndices.count > 1 {
+ let multiSelectionVC = tunnelDetailContentVC as? ButtonedDetailViewController ?? ButtonedDetailViewController()
+ multiSelectionVC.setButtonTitle(tr(format: "macButtonDeleteTunnels (%d)", tunnelIndices.count))
+ multiSelectionVC.onButtonClicked = { [weak tunnelsListVC] in
+ tunnelsListVC?.handleRemoveTunnelAction()
+ }
+ setTunnelDetailContentVC(multiSelectionVC)
+ self.tunnelDetailVC = nil
+ }
+ }
+
+ func tunnelsListEmpty() {
+ let noTunnelsVC = ButtonedDetailViewController()
+ noTunnelsVC.setButtonTitle(tr("macButtonImportTunnels"))
+ noTunnelsVC.onButtonClicked = { [weak self] in
+ guard let self = self else { return }
+ ImportPanelPresenter.presentImportPanel(tunnelsManager: self.tunnelsManager, sourceVC: self)
+ }
+ setTunnelDetailContentVC(noTunnelsVC)
+ self.tunnelDetailVC = nil
+ }
+}
+
+extension ManageTunnelsRootViewController {
+ override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? {
+ switch action {
+ case #selector(TunnelsListTableViewController.handleViewLogAction),
+ #selector(TunnelsListTableViewController.handleAddEmptyTunnelAction),
+ #selector(TunnelsListTableViewController.handleImportTunnelAction),
+ #selector(TunnelsListTableViewController.handleExportTunnelsAction),
+ #selector(TunnelsListTableViewController.handleRemoveTunnelAction):
+ return tunnelsListVC
+ case #selector(TunnelDetailTableViewController.handleToggleActiveStatusAction),
+ #selector(TunnelDetailTableViewController.handleEditTunnelAction):
+ return tunnelDetailVC
+ default:
+ return super.supplementalTarget(forAction: action, sender: sender)
+ }
+ }
+}