diff options
Diffstat (limited to '')
-rw-r--r-- | WireGuard/WireGuard/UI/iOS/SharedViews/KeyValueCell.swift (renamed from WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailKeyValueCell.swift) | 14 | ||||
-rw-r--r-- | WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailActivateOnDemandCell.swift | 40 | ||||
-rw-r--r-- | WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailButtonCell.swift | 55 | ||||
-rw-r--r-- | WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailStatusCell.swift | 85 | ||||
-rw-r--r-- | WireGuard/WireGuard/UI/iOS/TunnelDetail/TunnelDetailTableViewController.swift | 85 |
5 files changed, 70 insertions, 209 deletions
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/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 |