aboutsummaryrefslogtreecommitdiffstats
path: root/WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift
diff options
context:
space:
mode:
Diffstat (limited to 'WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift')
-rw-r--r--WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift158
1 files changed, 158 insertions, 0 deletions
diff --git a/WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift b/WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift
new file mode 100644
index 00000000..48956eb9
--- /dev/null
+++ b/WireGuard/WireGuard/UI/iOS/SharedViews/EditableKeyValueCell.swift
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018 WireGuard LLC. All Rights Reserved.
+
+import UIKit
+
+class EditableKeyValueCell: UITableViewCell {
+ var key: String {
+ get { return keyLabel.text ?? "" }
+ set(value) { keyLabel.text = value }
+ }
+ var value: String {
+ get { return valueTextField.text ?? "" }
+ set(value) { valueTextField.text = value }
+ }
+ var placeholderText: String {
+ get { return valueTextField.placeholder ?? "" }
+ set(value) { valueTextField.placeholder = value }
+ }
+ var isValueValid = true {
+ didSet {
+ if isValueValid {
+ keyLabel.textColor = .black
+ } else {
+ keyLabel.textColor = .red
+ }
+ }
+ }
+ var keyboardType: UIKeyboardType {
+ get { return valueTextField.keyboardType }
+ set(value) { valueTextField.keyboardType = value }
+ }
+
+ var onValueChanged: ((String) -> Void)?
+ var onValueBeingEdited: ((String) -> Void)?
+
+ let keyLabel: UILabel = {
+ let keyLabel = UILabel()
+ keyLabel.font = UIFont.preferredFont(forTextStyle: .body)
+ keyLabel.adjustsFontForContentSizeCategory = true
+ return keyLabel
+ }()
+
+ let valueTextField: UITextField = {
+ let valueTextField = UITextField()
+ valueTextField.font = UIFont.preferredFont(forTextStyle: .body)
+ valueTextField.adjustsFontForContentSizeCategory = true
+ valueTextField.autocapitalizationType = .none
+ valueTextField.autocorrectionType = .no
+ valueTextField.spellCheckingType = .no
+ return valueTextField
+ }()
+
+ var isStackedHorizontally = false
+ var isStackedVertically = false
+ var contentSizeBasedConstraints = [NSLayoutConstraint]()
+
+ private var textFieldValueOnBeginEditing: String = ""
+
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+
+ contentView.addSubview(keyLabel)
+ keyLabel.translatesAutoresizingMaskIntoConstraints = false
+ keyLabel.textAlignment = .right
+ let widthRatioConstraint = NSLayoutConstraint(item: keyLabel, attribute: .width,
+ relatedBy: .equal,
+ toItem: self, attribute: .width,
+ multiplier: 0.4, constant: 0)
+ // The "Persistent Keepalive" key doesn't fit into 0.4 * width on the iPhone SE,
+ // so set a CR priority > the 0.4-constraint's priority.
+ widthRatioConstraint.priority = .defaultHigh + 1
+ keyLabel.setContentCompressionResistancePriority(.defaultHigh + 2, for: .horizontal)
+ NSLayoutConstraint.activate([
+ keyLabel.leftAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leftAnchor),
+ keyLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 0.5),
+ widthRatioConstraint
+ ])
+
+ contentView.addSubview(valueTextField)
+ valueTextField.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ valueTextField.rightAnchor.constraint(equalTo: contentView.layoutMarginsGuide.rightAnchor),
+ contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: valueTextField.bottomAnchor, multiplier: 0.5)
+ ])
+ valueTextField.delegate = self
+
+ configureForContentSize()
+ }
+
+ func configureForContentSize() {
+ var constraints = [NSLayoutConstraint]()
+ if traitCollection.preferredContentSizeCategory.isAccessibilityCategory {
+ // Stack vertically
+ if !isStackedVertically {
+ constraints = [
+ valueTextField.topAnchor.constraint(equalToSystemSpacingBelow: keyLabel.bottomAnchor, multiplier: 0.5),
+ valueTextField.leftAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leftAnchor),
+ keyLabel.rightAnchor.constraint(equalTo: contentView.layoutMarginsGuide.rightAnchor)
+ ]
+ isStackedVertically = true
+ isStackedHorizontally = false
+ }
+ } else {
+ // Stack horizontally
+ if !isStackedHorizontally {
+ constraints = [
+ contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: keyLabel.bottomAnchor, multiplier: 0.5),
+ valueTextField.leftAnchor.constraint(equalToSystemSpacingAfter: keyLabel.rightAnchor, multiplier: 1),
+ valueTextField.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 0.5)
+ ]
+ isStackedHorizontally = true
+ isStackedVertically = false
+ }
+ }
+ if !constraints.isEmpty {
+ NSLayoutConstraint.deactivate(contentSizeBasedConstraints)
+ NSLayoutConstraint.activate(constraints)
+ contentSizeBasedConstraints = constraints
+ }
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func prepareForReuse() {
+ super.prepareForReuse()
+ key = ""
+ value = ""
+ placeholderText = ""
+ isValueValid = true
+ keyboardType = .default
+ onValueChanged = nil
+ onValueBeingEdited = nil
+ configureForContentSize()
+ }
+}
+
+extension EditableKeyValueCell: UITextFieldDelegate {
+ func textFieldDidBeginEditing(_ textField: UITextField) {
+ textFieldValueOnBeginEditing = textField.text ?? ""
+ isValueValid = true
+ }
+ func textFieldDidEndEditing(_ textField: UITextField) {
+ let isModified = (textField.text ?? "" != textFieldValueOnBeginEditing)
+ guard isModified else { return }
+ if let onValueChanged = onValueChanged {
+ onValueChanged(textField.text ?? "")
+ }
+ }
+ func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
+ if let onValueBeingEdited = onValueBeingEdited {
+ let modifiedText = ((textField.text ?? "") as NSString).replacingCharacters(in: range, with: string)
+ onValueBeingEdited(modifiedText)
+ }
+ return true
+ }
+}