diff options
author | 2018-12-14 17:12:59 -0600 | |
---|---|---|
committer | 2018-12-14 17:15:22 -0600 | |
commit | 7a24f18eb753180800f9b44a767b0d59e4e702b7 (patch) | |
tree | 0e02b3ff59a672b0b25eb7bcc195e23730abec40 /WireGuard/WireGuard/UI/iOS | |
parent | Prettier log time format (diff) | |
download | wireguard-apple-7a24f18eb753180800f9b44a767b0d59e4e702b7.tar.xz wireguard-apple-7a24f18eb753180800f9b44a767b0d59e4e702b7.zip |
Most similar views now shared between ViewControllers
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
Diffstat (limited to '')
22 files changed, 172 insertions, 380 deletions
diff --git a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift index 3146346..428f732 100644 --- a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift +++ b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift @@ -15,7 +15,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Logger.configureGlobal(withFilePath: FileManager.appLogFileURL?.path) let window = UIWindow(frame: UIScreen.main.bounds) - window.backgroundColor = UIColor.white + window.backgroundColor = .white self.window = window let mainVC = MainViewController() diff --git a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditReadOnlyKeyValueCell.swift b/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditReadOnlyKeyValueCell.swift index 48c8798..15d58d6 100644 --- a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditReadOnlyKeyValueCell.swift +++ b/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditReadOnlyKeyValueCell.swift @@ -6,29 +6,36 @@ import UIKit class TunnelEditReadOnlyKeyValueCell: CopyableLabelTableViewCell { var key: String { get { return keyLabel.text ?? "" } - set(value) {keyLabel.text = value } + set(value) { keyLabel.text = value } } var value: String { get { return valueLabel.text } set(value) { valueLabel.text = value } } - let keyLabel: UILabel - let valueLabel: ScrollableLabel + override var textToCopy: String? { + return valueLabel.text + } - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - keyLabel = UILabel() + let keyLabel: UILabel = { + let keyLabel = UILabel() keyLabel.font = UIFont.preferredFont(forTextStyle: .body) keyLabel.adjustsFontForContentSizeCategory = true - valueLabel = ScrollableLabel() + keyLabel.textColor = .gray + return keyLabel + }() + + let valueLabel: ScrollableLabel = { + let valueLabel = ScrollableLabel() valueLabel.label.font = UIFont.preferredFont(forTextStyle: .body) valueLabel.label.adjustsFontForContentSizeCategory = true - + valueLabel.textColor = .gray + return valueLabel + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - keyLabel.textColor = UIColor.gray - valueLabel.textColor = UIColor.gray - contentView.addSubview(keyLabel) keyLabel.translatesAutoresizingMaskIntoConstraints = false keyLabel.textAlignment = .right @@ -44,7 +51,7 @@ class TunnelEditReadOnlyKeyValueCell: CopyableLabelTableViewCell { keyLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), keyLabel.leftAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leftAnchor), widthRatioConstraint - ]) + ]) contentView.addSubview(valueLabel) valueLabel.translatesAutoresizingMaskIntoConstraints = false @@ -52,11 +59,7 @@ class TunnelEditReadOnlyKeyValueCell: CopyableLabelTableViewCell { valueLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), valueLabel.leftAnchor.constraint(equalToSystemSpacingAfter: keyLabel.rightAnchor, multiplier: 1), valueLabel.rightAnchor.constraint(equalTo: contentView.layoutMarginsGuide.rightAnchor) - ]) - } - - override var textToCopy: String? { - return self.valueLabel.text + ]) } required init?(coder aDecoder: NSCoder) { diff --git a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditTableViewController.swift b/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditTableViewController.swift index 8d055d2..393294e 100644 --- a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditTableViewController.swift @@ -72,18 +72,18 @@ class TunnelEditTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() - self.title = tunnel == nil ? "New configuration" : "Edit configuration" - self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveTapped)) - self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped)) - - self.tableView.estimatedRowHeight = 44 - self.tableView.rowHeight = UITableView.automaticDimension - - self.tableView.register(TunnelEditKeyValueCell.self) - self.tableView.register(TunnelEditReadOnlyKeyValueCell.self) - self.tableView.register(TunnelEditButtonCell.self) - self.tableView.register(TunnelEditSwitchCell.self) - self.tableView.register(TunnelEditSelectionListCell.self) + title = tunnel == nil ? "New configuration" : "Edit configuration" + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveTapped)) + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped)) + + tableView.estimatedRowHeight = 44 + tableView.rowHeight = UITableView.automaticDimension + + tableView.register(EditableKeyValueCell.self) + tableView.register(TunnelEditReadOnlyKeyValueCell.self) + tableView.register(ButtonCell.self) + tableView.register(SwitchCell.self) + tableView.register(CheckmarkCell.self) } private func loadSections() { @@ -95,13 +95,13 @@ class TunnelEditTableViewController: UITableViewController { } @objc func saveTapped() { - self.tableView.endEditing(false) + tableView.endEditing(false) let tunnelSaveResult = tunnelViewModel.save() switch tunnelSaveResult { case .error(let errorMessage): let erroringConfiguration = (tunnelViewModel.interfaceData.validatedConfiguration == nil) ? "Interface" : "Peer" ErrorPresenter.showErrorAlert(title: "Invalid \(erroringConfiguration)", message: errorMessage, from: self) - self.tableView.reloadData() // Highlight erroring fields + tableView.reloadData() // Highlight erroring fields case .saved(let tunnelConfiguration): if let tunnel = tunnel { // We're modifying an existing tunnel @@ -133,7 +133,7 @@ class TunnelEditTableViewController: UITableViewController { @objc func cancelTapped() { dismiss(animated: true, completion: nil) - self.delegate?.tunnelEditingCancelled() + delegate?.tunnelEditingCancelled() } } @@ -201,7 +201,7 @@ extension TunnelEditTableViewController { } private func generateKeyPairCell(for tableView: UITableView, at indexPath: IndexPath, with field: TunnelViewModel.InterfaceField) -> UITableViewCell { - let cell: TunnelEditButtonCell = tableView.dequeueReusableCell(for: indexPath) + let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath) cell.buttonText = field.rawValue cell.onTapped = { [weak self] in guard let self = self else { return } @@ -225,7 +225,7 @@ extension TunnelEditTableViewController { } private func interfaceFieldKeyValueCell(for tableView: UITableView, at indexPath: IndexPath, with field: TunnelViewModel.InterfaceField) -> UITableViewCell { - let cell: TunnelEditKeyValueCell = tableView.dequeueReusableCell(for: indexPath) + let cell: EditableKeyValueCell = tableView.dequeueReusableCell(for: indexPath) cell.key = field.rawValue switch field { @@ -287,7 +287,7 @@ extension TunnelEditTableViewController { } private func deletePeerCell(for tableView: UITableView, at indexPath: IndexPath, peerData: TunnelViewModel.PeerData, field: TunnelViewModel.PeerField) -> UITableViewCell { - let cell: TunnelEditButtonCell = tableView.dequeueReusableCell(for: indexPath) + let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath) cell.buttonText = field.rawValue cell.hasDestructiveAction = true cell.onTapped = { [weak self, weak peerData] in @@ -313,7 +313,7 @@ extension TunnelEditTableViewController { } private func excludePrivateIPsCell(for tableView: UITableView, at indexPath: IndexPath, peerData: TunnelViewModel.PeerData, field: TunnelViewModel.PeerField) -> UITableViewCell { - let cell: TunnelEditSwitchCell = tableView.dequeueReusableCell(for: indexPath) + let cell: SwitchCell = tableView.dequeueReusableCell(for: indexPath) cell.message = field.rawValue cell.isEnabled = peerData.shouldAllowExcludePrivateIPsControl cell.isOn = peerData.excludePrivateIPsValue @@ -328,7 +328,7 @@ extension TunnelEditTableViewController { } private func peerFieldKeyValueCell(for tableView: UITableView, at indexPath: IndexPath, peerData: TunnelViewModel.PeerData, field: TunnelViewModel.PeerField) -> UITableViewCell { - let cell: TunnelEditKeyValueCell = tableView.dequeueReusableCell(for: indexPath) + let cell: EditableKeyValueCell = tableView.dequeueReusableCell(for: indexPath) cell.key = field.rawValue switch field { @@ -377,7 +377,7 @@ extension TunnelEditTableViewController { } private func addPeerCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { - let cell: TunnelEditButtonCell = tableView.dequeueReusableCell(for: indexPath) + let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath) cell.buttonText = "Add peer" cell.onTapped = { [weak self] in guard let self = self else { return } @@ -398,7 +398,7 @@ extension TunnelEditTableViewController { private func onDemandCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { if indexPath.row == 0 { - let cell: TunnelEditSwitchCell = tableView.dequeueReusableCell(for: indexPath) + let cell: SwitchCell = tableView.dequeueReusableCell(for: indexPath) cell.message = "Activate on demand" cell.isOn = activateOnDemandSetting.isActivateOnDemandEnabled cell.onSwitchToggled = { [weak self] isOn in @@ -419,7 +419,7 @@ extension TunnelEditTableViewController { } return cell } else { - let cell: TunnelEditSelectionListCell = tableView.dequeueReusableCell(for: indexPath) + let cell: CheckmarkCell = tableView.dequeueReusableCell(for: indexPath) let rowOption = activateOnDemandOptions[indexPath.row - 1] let selectedOption = activateOnDemandSetting.activateOnDemandOption assert(selectedOption != .none) @@ -455,7 +455,7 @@ extension TunnelEditTableViewController { alert.popoverPresentationController?.sourceView = sourceView alert.popoverPresentationController?.sourceRect = sourceView.bounds - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } } diff --git a/WireGuard/WireGuard/UI/iOS/MainViewController.swift b/WireGuard/WireGuard/UI/iOS/MainViewController.swift index 2fc46b2..82e6f81 100644 --- a/WireGuard/WireGuard/UI/iOS/MainViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/MainViewController.swift @@ -12,20 +12,20 @@ class MainViewController: UISplitViewController { init() { let detailVC = UIViewController() - detailVC.view.backgroundColor = UIColor.white + detailVC.view.backgroundColor = .white let detailNC = UINavigationController(rootViewController: detailVC) let masterVC = TunnelsListTableViewController() let masterNC = UINavigationController(rootViewController: masterVC) - self.tunnelsListVC = masterVC + tunnelsListVC = masterVC super.init(nibName: nil, bundle: nil) - self.viewControllers = [ masterNC, detailNC ] + viewControllers = [ masterNC, detailNC ] // State restoration - self.restorationIdentifier = "MainVC" + restorationIdentifier = "MainVC" masterNC.restorationIdentifier = "MasterNC" detailNC.restorationIdentifier = "DetailNC" } @@ -35,10 +35,10 @@ class MainViewController: UISplitViewController { } override func viewDidLoad() { - self.delegate = self + delegate = self // On iPad, always show both masterVC and detailVC, even in portrait mode, like the Settings app - self.preferredDisplayMode = .allVisible + preferredDisplayMode = .allVisible // Create the tunnels manager, and when it's ready, inform tunnelsListVC TunnelsManager.create { [weak self] result in @@ -56,7 +56,7 @@ class MainViewController: UISplitViewController { tunnelsManager.activationDelegate = self self.onTunnelsManagerReady?(tunnelsManager) - self.onTunnelsManagerReady = nil + self.onTunnelsManagerReady = nil } } } diff --git a/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift b/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift index a03b709..1e231ec 100644 --- a/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift @@ -2,7 +2,6 @@ // Copyright © 2018 WireGuard LLC. All Rights Reserved. import AVFoundation -import CoreData import UIKit protocol QRScanViewControllerDelegate: class { @@ -18,8 +17,8 @@ class QRScanViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - self.title = "Scan QR code" - self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped)) + title = "Scan QR code" + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped)) let tipLabel = UILabel() tipLabel.text = "Tip: Generate with `qrencode -t ansiutf8 < tunnel.conf`" @@ -102,7 +101,7 @@ class QRScanViewController: UIViewController { } } - previewLayer?.frame = self.view.bounds + previewLayer?.frame = view.bounds } func scanDidComplete(withCode code: String) { diff --git a/WireGuard/WireGuard/UI/iOS/Settings/SettingsButtonCell.swift b/WireGuard/WireGuard/UI/iOS/Settings/SettingsButtonCell.swift deleted file mode 100644 index d795ab4..0000000 --- a/WireGuard/WireGuard/UI/iOS/Settings/SettingsButtonCell.swift +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import UIKit - -class SettingsButtonCell: UITableViewCell { - var buttonText: String { - get { return button.title(for: .normal) ?? "" } - set(value) { button.setTitle(value, for: .normal) } - } - var onTapped: (() -> Void)? - - let button: UIButton = { - let button = UIButton(type: .system) - button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) - button.titleLabel?.adjustsFontForContentSizeCategory = true - return button - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - contentView.addSubview(button) - button.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - button.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor), - contentView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: button.bottomAnchor), - button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor) - ]) - - button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) - } - - @objc func buttonTapped() { - onTapped?() - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func prepareForReuse() { - super.prepareForReuse() - buttonText = "" - onTapped = nil - } -} diff --git a/WireGuard/WireGuard/UI/iOS/Settings/SettingsKeyValueCell.swift b/WireGuard/WireGuard/UI/iOS/Settings/SettingsKeyValueCell.swift deleted file mode 100644 index 532f1d1..0000000 --- a/WireGuard/WireGuard/UI/iOS/Settings/SettingsKeyValueCell.swift +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import UIKit - -class SettingsKeyValueCell: UITableViewCell { - var key: String { - get { return textLabel?.text ?? "" } - set(value) { textLabel?.text = value } - } - var value: String { - get { return detailTextLabel?.text ?? "" } - set(value) { detailTextLabel?.text = value } - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .value1, reuseIdentifier: SettingsKeyValueCell.reuseIdentifier) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func prepareForReuse() { - super.prepareForReuse() - key = "" - value = "" - } -} diff --git a/WireGuard/WireGuard/UI/iOS/Settings/SettingsTableViewController.swift b/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift index 5e8aee6..b583c5b 100644 --- a/WireGuard/WireGuard/UI/iOS/Settings/SettingsTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift @@ -40,15 +40,15 @@ class SettingsTableViewController: UITableViewController { tableView.rowHeight = UITableView.automaticDimension tableView.allowsSelection = false - tableView.register(SettingsKeyValueCell.self) - tableView.register(SettingsButtonCell.self) + tableView.register(KeyValueCell.self) + tableView.register(ButtonCell.self) tableView.tableFooterView = UIImageView(image: UIImage(named: "wireguard.pdf")) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - guard let logo = self.tableView.tableFooterView else { return } + guard let logo = tableView.tableFooterView else { return } let bottomPadding = max(tableView.layoutMargins.bottom, 10) let fullHeight = max(tableView.contentSize.height, tableView.bounds.size.height - tableView.layoutMargins.top - bottomPadding) @@ -167,7 +167,8 @@ extension SettingsTableViewController { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let field = settingsFieldsBySection[indexPath.section][indexPath.row] if field == .iosAppVersion || field == .goBackendVersion { - let cell: SettingsKeyValueCell = tableView.dequeueReusableCell(for: indexPath) + let cell: KeyValueCell = tableView.dequeueReusableCell(for: indexPath) + cell.copyableGesture = false cell.key = field.rawValue if field == .iosAppVersion { var appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown version" @@ -180,7 +181,7 @@ extension SettingsTableViewController { } return cell } else if field == .exportZipArchive { - let cell: SettingsButtonCell = tableView.dequeueReusableCell(for: indexPath) + let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath) cell.buttonText = field.rawValue cell.onTapped = { [weak self] in self?.exportConfigurationsAsZipFile(sourceView: cell.button) @@ -188,7 +189,7 @@ extension SettingsTableViewController { return cell } else { assert(field == .exportLogFile) - let cell: SettingsButtonCell = tableView.dequeueReusableCell(for: indexPath) + let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath) cell.buttonText = field.rawValue cell.onTapped = { [weak self] in self?.exportLogForLastActivatedTunnel(sourceView: cell.button) diff --git a/WireGuard/WireGuard/UI/iOS/TunnelList/BorderedTextButton.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/BorderedTextButton.swift index 5114c09..94b76d6 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelList/BorderedTextButton.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/BorderedTextButton.swift @@ -33,9 +33,9 @@ class BorderedTextButton: UIView { addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ - button.centerXAnchor.constraint(equalTo: self.centerXAnchor), - button.centerYAnchor.constraint(equalTo: self.centerYAnchor) - ]) + button.centerXAnchor.constraint(equalTo: centerXAnchor), + button.centerYAnchor.constraint(equalTo: centerYAnchor) + ]) button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) } diff --git a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditButtonCell.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/ButtonCell.swift index af70183..4702993 100644 --- a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditButtonCell.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/ButtonCell.swift @@ -3,14 +3,14 @@ import UIKit -class TunnelEditButtonCell: UITableViewCell { +class ButtonCell: UITableViewCell { var buttonText: String { get { return button.title(for: .normal) ?? "" } set(value) { button.setTitle(value, for: .normal) } } var hasDestructiveAction: Bool { - get { return button.tintColor == UIColor.red } - set(value) { button.tintColor = value ? UIColor.red : buttonStandardTintColor } + get { return button.tintColor == .red } + set(value) { button.tintColor = value ? .red : buttonStandardTintColor } } var onTapped: (() -> Void)? diff --git a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditSectionListCell.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/CheckmarkCell.swift index ca0352e..db4b6c9 100644 --- a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditSectionListCell.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/CheckmarkCell.swift @@ -3,7 +3,7 @@ import UIKit -class TunnelEditSelectionListCell: UITableViewCell { +class CheckmarkCell: UITableViewCell { var message: String { get { return textLabel?.text ?? "" } set(value) { textLabel!.text = value } @@ -13,6 +13,7 @@ class TunnelEditSelectionListCell: UITableViewCell { accessoryType = isChecked ? .checkmark : .none } } + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { isChecked = false super.init(style: .default, reuseIdentifier: reuseIdentifier) diff --git a/WireGuard/WireGuard/UI/iOS/CopyableLabelTableViewCell.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/CopyableLabelTableViewCell.swift index daddf0a..93a9ef7 100644 --- a/WireGuard/WireGuard/UI/iOS/CopyableLabelTableViewCell.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/CopyableLabelTableViewCell.swift @@ -17,13 +17,13 @@ class CopyableLabelTableViewCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(_:))) - self.addGestureRecognizer(gestureRecognizer) - self.isUserInteractionEnabled = true + addGestureRecognizer(gestureRecognizer) + isUserInteractionEnabled = true } // MARK: - UIGestureRecognizer @objc func handleTapGesture(_ recognizer: UIGestureRecognizer) { - if !self.copyableGesture { + if !copyableGesture { return } guard recognizer.state == .recognized else { return } @@ -31,7 +31,7 @@ class CopyableLabelTableViewCell: UITableViewCell { if let recognizerView = recognizer.view, let recognizerSuperView = recognizerView.superview, recognizerView.becomeFirstResponder() { let menuController = UIMenuController.shared - menuController.setTargetRect(self.detailTextLabel?.frame ?? recognizerView.frame, in: self.detailTextLabel?.superview ?? recognizerSuperView) + menuController.setTargetRect(detailTextLabel?.frame ?? recognizerView.frame, in: detailTextLabel?.superview ?? recognizerSuperView) menuController.setMenuVisible(true, animated: true) } } @@ -50,6 +50,6 @@ class CopyableLabelTableViewCell: UITableViewCell { override func prepareForReuse() { super.prepareForReuse() - self.copyableGesture = true + copyableGesture = true } } diff --git a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditKeyValueCell.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift index 432d75b..48956eb 100644 --- a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditKeyValueCell.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift @@ -3,10 +3,10 @@ import UIKit -class TunnelEditKeyValueCell: UITableViewCell { +class EditableKeyValueCell: UITableViewCell { var key: String { get { return keyLabel.text ?? "" } - set(value) {keyLabel.text = value } + set(value) { keyLabel.text = value } } var value: String { get { return valueTextField.text ?? "" } @@ -89,7 +89,7 @@ class TunnelEditKeyValueCell: UITableViewCell { func configureForContentSize() { var constraints = [NSLayoutConstraint]() - if self.traitCollection.preferredContentSizeCategory.isAccessibilityCategory { + if traitCollection.preferredContentSizeCategory.isAccessibilityCategory { // Stack vertically if !isStackedVertically { constraints = [ @@ -113,9 +113,9 @@ class TunnelEditKeyValueCell: UITableViewCell { } } if !constraints.isEmpty { - NSLayoutConstraint.deactivate(self.contentSizeBasedConstraints) + NSLayoutConstraint.deactivate(contentSizeBasedConstraints) NSLayoutConstraint.activate(constraints) - self.contentSizeBasedConstraints = constraints + contentSizeBasedConstraints = constraints } } @@ -136,7 +136,7 @@ class TunnelEditKeyValueCell: UITableViewCell { } } -extension TunnelEditKeyValueCell: UITextFieldDelegate { +extension EditableKeyValueCell: UITextFieldDelegate { func textFieldDidBeginEditing(_ textField: UITextField) { textFieldValueOnBeginEditing = textField.text ?? "" isValueValid = true diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailKeyValueCell.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/KeyValueCell.swift index cbe1c14..78026ea 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailKeyValueCell.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/KeyValueCell.swift @@ -3,7 +3,7 @@ import UIKit -class TunnelDetailKeyValueCell: CopyableLabelTableViewCell { +class KeyValueCell: CopyableLabelTableViewCell { var key: String { get { return keyLabel.text ?? "" } set(value) { keyLabel.text = value } @@ -14,7 +14,7 @@ class TunnelDetailKeyValueCell: CopyableLabelTableViewCell { } override var textToCopy: String? { - return self.valueLabel.text + return valueLabel.text } let keyLabel: UILabel = { @@ -46,14 +46,14 @@ class TunnelDetailKeyValueCell: CopyableLabelTableViewCell { NSLayoutConstraint.activate([ keyLabel.leftAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leftAnchor), keyLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 0.5) - ]) + ]) contentView.addSubview(valueLabel) valueLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ valueLabel.rightAnchor.constraint(equalTo: contentView.layoutMarginsGuide.rightAnchor), contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: valueLabel.bottomAnchor, multiplier: 0.5) - ]) + ]) keyLabel.setContentCompressionResistancePriority(.defaultHigh + 1, for: .horizontal) keyLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) @@ -64,7 +64,7 @@ class TunnelDetailKeyValueCell: CopyableLabelTableViewCell { func configureForContentSize() { var constraints = [NSLayoutConstraint]() - if self.traitCollection.preferredContentSizeCategory.isAccessibilityCategory { + if traitCollection.preferredContentSizeCategory.isAccessibilityCategory { // Stack vertically if !isStackedVertically { constraints = [ @@ -88,9 +88,9 @@ class TunnelDetailKeyValueCell: CopyableLabelTableViewCell { } } if !constraints.isEmpty { - NSLayoutConstraint.deactivate(self.contentSizeBasedConstraints) + NSLayoutConstraint.deactivate(contentSizeBasedConstraints) NSLayoutConstraint.activate(constraints) - self.contentSizeBasedConstraints = constraints + contentSizeBasedConstraints = constraints } } diff --git a/WireGuard/WireGuard/UI/iOS/ScrollableLabel.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/ScrollableLabel.swift index bd6f547..bd6f547 100644 --- a/WireGuard/WireGuard/UI/iOS/ScrollableLabel.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/ScrollableLabel.swift diff --git a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditSwitchCell.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/SwitchCell.swift index 658fb95..d0c29aa 100644 --- a/WireGuard/WireGuard/UI/iOS/EditTunnel/TunnelEditSwitchCell.swift +++ b/WireGuard/WireGuard/UI/iOS/SharedViews/SwitchCell.swift @@ -3,10 +3,10 @@ import UIKit -class TunnelEditSwitchCell: UITableViewCell { +class SwitchCell: UITableViewCell { var message: String { get { return textLabel?.text ?? "" } - set(value) { textLabel!.text = value } + set(value) { textLabel?.text = value } } var isOn: Bool { get { return switchView.isOn } @@ -16,31 +16,32 @@ class TunnelEditSwitchCell: UITableViewCell { get { return switchView.isEnabled } set(value) { switchView.isEnabled = value - textLabel?.textColor = value ? UIColor.black : UIColor.gray + textLabel?.textColor = value ? .black : .gray } } var onSwitchToggled: ((Bool) -> Void)? - let switchView: UISwitch + let switchView = UISwitch() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - switchView = UISwitch() super.init(style: .default, reuseIdentifier: reuseIdentifier) + accessoryView = switchView switchView.addTarget(self, action: #selector(switchToggled), for: .valueChanged) } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } @objc func switchToggled() { onSwitchToggled?(switchView.isOn) } - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - override func prepareForReuse() { super.prepareForReuse() + isEnabled = true message = "" isOn = false } diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailActivateOnDemandCell.swift b/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailActivateOnDemandCell.swift deleted file mode 100644 index 9507c45..0000000 --- a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailActivateOnDemandCell.swift +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import UIKit - -class TunnelDetailActivateOnDemandCell: UITableViewCell { - var tunnel: TunnelContainer? { - didSet(value) { - update(from: tunnel?.activateOnDemandSetting()) - onDemandStatusObservervationToken = tunnel?.observe(\.isActivateOnDemandEnabled) { [weak self] tunnel, _ in - self?.update(from: tunnel.activateOnDemandSetting()) - } - } - } - - var onDemandStatusObservervationToken: AnyObject? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .value1, reuseIdentifier: reuseIdentifier) - textLabel?.text = "Activate on demand" - textLabel?.font = UIFont.preferredFont(forTextStyle: .body) - textLabel?.adjustsFontForContentSizeCategory = true - detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body) - detailTextLabel?.adjustsFontForContentSizeCategory = true - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func update(from activateOnDemandSetting: ActivateOnDemandSetting?) { - detailTextLabel?.text = TunnelViewModel.activateOnDemandDetailText(for: activateOnDemandSetting) - } - - override func prepareForReuse() { - super.prepareForReuse() - textLabel?.text = "Activate on demand" - detailTextLabel?.text = "" - } -} diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailButtonCell.swift b/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailButtonCell.swift deleted file mode 100644 index 8710616..0000000 --- a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailButtonCell.swift +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import UIKit - -class TunnelDetailButtonCell: UITableViewCell { - var buttonText: String { - get { return button.title(for: .normal) ?? "" } - set(value) { button.setTitle(value, for: .normal) } - } - var hasDestructiveAction: Bool { - get { return button.tintColor == UIColor.red } - set(value) { button.tintColor = value ? UIColor.red : buttonStandardTintColor } - } - var onTapped: (() -> Void)? - - let button: UIButton = { - let button = UIButton(type: .system) - button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) - button.titleLabel?.adjustsFontForContentSizeCategory = true - return button - }() - - var buttonStandardTintColor: UIColor - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - buttonStandardTintColor = button.tintColor - super.init(style: style, reuseIdentifier: reuseIdentifier) - - contentView.addSubview(button) - button.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - button.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor), - contentView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: button.bottomAnchor), - button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor) - ]) - - button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) - } - - @objc func buttonTapped() { - onTapped?() - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func prepareForReuse() { - super.prepareForReuse() - buttonText = "" - onTapped = nil - hasDestructiveAction = false - } -} diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailStatusCell.swift b/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailStatusCell.swift deleted file mode 100644 index 0dd1ee9..0000000 --- a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailStatusCell.swift +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018 WireGuard LLC. All Rights Reserved. - -import UIKit - -class TunnelDetailStatusCell: UITableViewCell { - var tunnel: TunnelContainer? { - didSet(value) { - update(from: tunnel?.status) - statusObservervationToken = tunnel?.observe(\.status) { [weak self] tunnel, _ in - self?.update(from: tunnel.status) - } - } - } - var isSwitchInteractionEnabled: Bool { - get { return statusSwitch.isUserInteractionEnabled } - set(value) { statusSwitch.isUserInteractionEnabled = value } - } - var onSwitchToggled: ((Bool) -> Void)? - private var isOnSwitchToggledHandlerEnabled = true - - let statusSwitch: UISwitch - private var statusObservervationToken: AnyObject? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - statusSwitch = UISwitch() - super.init(style: .default, reuseIdentifier: TunnelDetailKeyValueCell.reuseIdentifier) - accessoryView = statusSwitch - - statusSwitch.addTarget(self, action: #selector(switchToggled), for: .valueChanged) - } - - @objc func switchToggled() { - if isOnSwitchToggledHandlerEnabled { - onSwitchToggled?(statusSwitch.isOn) - } - } - - private func update(from status: TunnelStatus?) { - guard let status = status else { - reset() - return - } - let text: String - switch status { - case .inactive: - text = "Inactive" - case .activating: - text = "Activating" - case .active: - text = "Active" - case .deactivating: - text = "Deactivating" - case .reasserting: - text = "Reactivating" - case .restarting: - text = "Restarting" - case .waiting: - text = "Waiting" - } - textLabel?.text = text - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) { [weak statusSwitch] in - guard let statusSwitch = statusSwitch else { return } - statusSwitch.isOn = !(status == .deactivating || status == .inactive) - statusSwitch.isUserInteractionEnabled = (status == .inactive || status == .active) - } - textLabel?.textColor = (status == .active || status == .inactive) ? UIColor.black : UIColor.gray - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func reset() { - textLabel?.text = "Invalid" - statusSwitch.isOn = false - textLabel?.textColor = UIColor.gray - statusSwitch.isUserInteractionEnabled = false - } - - override func prepareForReuse() { - super.prepareForReuse() - reset() - } -} diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailTableViewController.swift index af4cf83..ed48d0f 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailTableViewController.swift @@ -29,6 +29,8 @@ class TunnelDetailTableViewController: UITableViewController { let tunnel: TunnelContainer var tunnelViewModel: TunnelViewModel private var sections = [Section]() + private var onDemandStatusObservervationToken: AnyObject? + private var statusObservervationToken: AnyObject? init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer) { self.tunnelsManager = tunnelsManager @@ -41,22 +43,26 @@ class TunnelDetailTableViewController: UITableViewController { required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + deinit { + onDemandStatusObservervationToken = nil + statusObservervationToken = nil + } override func viewDidLoad() { super.viewDidLoad() - self.title = tunnelViewModel.interfaceData[.name] - self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped)) + title = tunnelViewModel.interfaceData[.name] + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped)) - self.tableView.estimatedRowHeight = 44 - self.tableView.rowHeight = UITableView.automaticDimension - self.tableView.allowsSelection = false - self.tableView.register(TunnelDetailStatusCell.self) - self.tableView.register(TunnelDetailKeyValueCell.self) - self.tableView.register(TunnelDetailButtonCell.self) - self.tableView.register(TunnelDetailActivateOnDemandCell.self) + tableView.estimatedRowHeight = 44 + tableView.rowHeight = UITableView.automaticDimension + tableView.allowsSelection = false + tableView.register(SwitchCell.self) + tableView.register(KeyValueCell.self) + tableView.register(ButtonCell.self) // State restoration - self.restorationIdentifier = "TunnelDetailVC:\(tunnel.name)" + restorationIdentifier = "TunnelDetailVC:\(tunnel.name)" } private func loadSections() { @@ -76,8 +82,7 @@ class TunnelDetailTableViewController: UITableViewController { present(editNC, animated: true) } - func showConfirmationAlert(message: String, buttonTitle: String, from sourceView: UIView, - onConfirmed: @escaping (() -> Void)) { + func showConfirmationAlert(message: String, buttonTitle: String, from sourceView: UIView, onConfirmed: @escaping (() -> Void)) { let destroyAction = UIAlertAction(title: buttonTitle, style: .destructive) { _ in onConfirmed() } @@ -90,7 +95,7 @@ class TunnelDetailTableViewController: UITableViewController { alert.popoverPresentationController?.sourceView = sourceView alert.popoverPresentationController?.sourceRect = sourceView.bounds - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } } @@ -100,8 +105,8 @@ extension TunnelDetailTableViewController: TunnelEditTableViewControllerDelegate func tunnelSaved(tunnel: TunnelContainer) { tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnel.tunnelConfiguration()) loadSections() - self.title = tunnel.name - self.tableView.reloadData() + title = tunnel.name + tableView.reloadData() } func tunnelEditingCancelled() { // Nothing to do @@ -161,8 +166,40 @@ extension TunnelDetailTableViewController { } private func statusCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { - let cell: TunnelDetailStatusCell = tableView.dequeueReusableCell(for: indexPath) - cell.tunnel = self.tunnel + let cell: SwitchCell = tableView.dequeueReusableCell(for: indexPath) + + let statusUpdate: (SwitchCell, TunnelStatus) -> Void = { cell, status in + let text: String + switch status { + case .inactive: + text = "Inactive" + case .activating: + text = "Activating" + case .active: + text = "Active" + case .deactivating: + text = "Deactivating" + case .reasserting: + text = "Reactivating" + case .restarting: + text = "Restarting" + case .waiting: + text = "Waiting" + } + cell.textLabel?.text = text + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) { [weak cell] in + cell?.switchView.isOn = !(status == .deactivating || status == .inactive) + cell?.switchView.isUserInteractionEnabled = (status == .inactive || status == .active) + } + cell.isEnabled = status == .active || status == .inactive + } + + statusUpdate(cell, tunnel.status) + statusObservervationToken = tunnel.observe(\.status) { [weak cell] tunnel, _ in + guard let cell = cell else { return } + statusUpdate(cell, tunnel.status) + } + cell.onSwitchToggled = { [weak self] isOn in guard let self = self else { return } if isOn { @@ -176,7 +213,7 @@ extension TunnelDetailTableViewController { private func interfaceCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { let field = tunnelViewModel.interfaceData.filterFieldsWithValueOrControl(interfaceFields: interfaceFields)[indexPath.row] - let cell: TunnelDetailKeyValueCell = tableView.dequeueReusableCell(for: indexPath) + let cell: KeyValueCell = tableView.dequeueReusableCell(for: indexPath) cell.key = field.rawValue cell.value = tunnelViewModel.interfaceData[field] return cell @@ -184,20 +221,24 @@ extension TunnelDetailTableViewController { private func peerCell(for tableView: UITableView, at indexPath: IndexPath, with peerData: TunnelViewModel.PeerData) -> UITableViewCell { let field = peerData.filterFieldsWithValueOrControl(peerFields: peerFields)[indexPath.row] - let cell: TunnelDetailKeyValueCell = tableView.dequeueReusableCell(for: indexPath) + let cell: KeyValueCell = tableView.dequeueReusableCell(for: indexPath) cell.key = field.rawValue cell.value = peerData[field] return cell } private func onDemandCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { - let cell: TunnelDetailActivateOnDemandCell = tableView.dequeueReusableCell(for: indexPath) - cell.tunnel = self.tunnel + let cell: KeyValueCell = tableView.dequeueReusableCell(for: indexPath) + cell.key = "Activate on demand" + cell.value = TunnelViewModel.activateOnDemandDetailText(for: tunnel.activateOnDemandSetting()) + onDemandStatusObservervationToken = tunnel.observe(\.isActivateOnDemandEnabled) { [weak cell] tunnel, _ in + cell?.value = TunnelViewModel.activateOnDemandDetailText(for: tunnel.activateOnDemandSetting()) + } return cell } private func deleteConfigurationCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { - let cell: TunnelDetailButtonCell = tableView.dequeueReusableCell(for: indexPath) + let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath) cell.buttonText = "Delete tunnel" cell.hasDestructiveAction = true cell.onTapped = { [weak self] in diff --git a/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelListCell.swift b/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelListCell.swift index f0a16bf..14a7194 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelListCell.swift +++ b/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelListCell.swift @@ -47,14 +47,14 @@ class TunnelListCell: UITableViewCell { NSLayoutConstraint.activate([ statusSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), contentView.rightAnchor.constraint(equalTo: statusSwitch.rightAnchor) - ]) + ]) contentView.addSubview(busyIndicator) busyIndicator.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ busyIndicator.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), statusSwitch.leftAnchor.constraint(equalToSystemSpacingAfter: busyIndicator.rightAnchor, multiplier: 1) - ]) + ]) contentView.addSubview(nameLabel) nameLabel.translatesAutoresizingMaskIntoConstraints = false @@ -66,7 +66,7 @@ class TunnelListCell: UITableViewCell { nameLabel.leftAnchor.constraint(equalToSystemSpacingAfter: contentView.layoutMarginsGuide.leftAnchor, multiplier: 1), busyIndicator.leftAnchor.constraint(equalToSystemSpacingAfter: nameLabel.rightAnchor, multiplier: 1), bottomAnchorConstraint - ]) + ]) accessoryType = .disclosureIndicator diff --git a/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelsListTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelsListTableViewController.swift index eda09af..0188c62 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelsListTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/TunnelList/TunnelsListTableViewController.swift @@ -96,7 +96,8 @@ class TunnelsListTableViewController: UIViewController { } @objc func addButtonTapped(sender: AnyObject) { - if self.tunnelsManager == nil { return } // Do nothing until we've loaded the tunnels + guard tunnelsManager != nil else { return } + let alert = UIAlertController(title: "", message: "Add a new WireGuard tunnel", preferredStyle: .actionSheet) let importFileAction = UIAlertAction(title: "Create from file or archive", style: .default) { [weak self] _ in self?.presentViewControllerForFileImport() @@ -125,29 +126,30 @@ class TunnelsListTableViewController: UIViewController { alert.popoverPresentationController?.sourceView = sender alert.popoverPresentationController?.sourceRect = sender.bounds } - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } @objc func settingsButtonTapped(sender: UIBarButtonItem!) { - if self.tunnelsManager == nil { return } // Do nothing until we've loaded the tunnels + guard tunnelsManager != nil else { return } + let settingsVC = SettingsTableViewController(tunnelsManager: tunnelsManager) let settingsNC = UINavigationController(rootViewController: settingsVC) settingsNC.modalPresentationStyle = .formSheet - self.present(settingsNC, animated: true) + present(settingsNC, animated: true) } func presentViewControllerForTunnelCreation(tunnelsManager: TunnelsManager, tunnelConfiguration: TunnelConfiguration?) { let editVC = TunnelEditTableViewController(tunnelsManager: tunnelsManager, tunnelConfiguration: tunnelConfiguration) let editNC = UINavigationController(rootViewController: editVC) editNC.modalPresentationStyle = .formSheet - self.present(editNC, animated: true) + present(editNC, animated: true) } func presentViewControllerForFileImport() { let documentTypes = ["com.wireguard.config.quick", String(kUTTypeText), String(kUTTypeZipArchive)] let filePicker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import) filePicker.delegate = self - self.present(filePicker, animated: true) + present(filePicker, animated: true) } func presentViewControllerForScanningQRCode() { @@ -155,7 +157,7 @@ class TunnelsListTableViewController: UIViewController { scanQRCodeVC.delegate = self let scanQRCodeNC = UINavigationController(rootViewController: scanQRCodeVC) scanQRCodeNC.modalPresentationStyle = .fullScreen - self.present(scanQRCodeNC, animated: true) + present(scanQRCodeNC, animated: true) } func importFromFile(url: URL, completionHandler: (() -> Void)?) { |