diff --git a/BluetoothExplorer/Controller/GATT Characteristic Editors/PnPIDCharacteristicViewController.swift b/BluetoothExplorer/Controller/GATT Characteristic Editors/PnPIDCharacteristicViewController.swift index a380e3e..e4a0bff 100644 --- a/BluetoothExplorer/Controller/GATT Characteristic Editors/PnPIDCharacteristicViewController.swift +++ b/BluetoothExplorer/Controller/GATT Characteristic Editors/PnPIDCharacteristicViewController.swift @@ -9,20 +9,17 @@ import UIKit import Bluetooth -final class PnPIDCharacteristicViewController: UIViewController, CharacteristicViewController, InstantiableViewController { +final class PnPIDCharacteristicViewController: UITableViewController, CharacteristicViewController, InstantiableViewController { typealias VendorIDSource = GATTPnPID.VendorIDSource - // MARK: - IB Outlets + // MARK: - Properties - @IBOutlet weak var vendorIDSourceTextField: UITextField! - @IBOutlet weak var vendorIDTextField: UITextField! - @IBOutlet weak var productIDTextField: UITextField! - @IBOutlet weak var productVersionTextField: UITextField! + private let cellIdentifier = "InputTextViewCell" - // MARK: - Properties + private var fields = [Field]() - var value = GATTPnPID(vendorIdSource: VendorIDSource(rawValue: 0x01)!, vendorId: 0, productId: 0, productVersion: 0) + var value = GATTPnPID(vendorIdSource: .fromAssignedNumbersDocument, vendorId: 0, productId: 0, productVersion: 0) var valueDidChange: ((GATTPnPID) -> ())? @@ -31,29 +28,139 @@ final class PnPIDCharacteristicViewController: UIViewController, CharacteristicV override func viewDidLoad() { super.viewDidLoad() - configureView() + fields = [.vendorIdSource("\(value.vendorIdSource)"), + .vendorId("\(value.vendorId)"), + .productId("\(value.productId)"), + .productVersionId("\(value.productVersion)"),] + + tableView.register(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier) + tableView.separatorStyle = .none } - // MARK: - Methods + // MARK: - UITableViewController + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return fields.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + let field = fields[indexPath.row] + let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! InputTextViewCell + cell.selectionStyle = .none + + configure(cell, field: field) + + return cell + } - func configureView() { + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard isViewLoaded else { return } + let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! InputTextViewCell + cell.inputTextView.textField.becomeFirstResponder() + } + + // MARK: - Methods + + func configure(_ cell: InputTextViewCell, field: Field) { - updateText() + cell.inputTextView.value = field.bluetoothValue + cell.inputTextView.posibleInputValues = field.posibleValues + cell.inputTextView.isEnabled = valueDidChange != nil + cell.inputTextView.keyboardType = field.keyboardType + cell.inputTextView.fieldLabelText = field.title + cell.inputTextView.placeholder = field.title + cell.inputTextView.validator = { value in + + guard value.trim() != "" + else { return .none } + + switch field { + case .vendorId(let value): + + guard let _ = UInt16(value) + else { return .error("Maximum value is 0xFFFF)") } + + case .productId(let value): + + guard let _ = UInt16(value) + else { return .error("Maximum value is 0xFFFF)") } + + case .productVersionId(let value): + + guard let _ = UInt16(value) + else { return .error("Maximum value is 0xFFFF)") } + + default: + break + } + + return .none + } } +} + +extension PnPIDCharacteristicViewController { - private func updateText() { + enum Field { + + case vendorIdSource(String) + case vendorId(String) + case productId(String) + case productVersionId(String) + + var title: String { + + switch self { + case .vendorIdSource: + return "Vendor ID Source" + + case .vendorId: + return "Vendor ID" + + case .productId: + return "Product ID" + + case .productVersionId: + return "Product Version ID" + } + } + + var bluetoothValue: String { + switch self { + case .vendorIdSource(let value): + return value + + case .vendorId(let value): + return value + + case .productId(let value): + return value + + case .productVersionId(let value): + return value + } + } - let enabled = valueDidChange != nil - vendorIDSourceTextField.isEnabled = enabled - vendorIDTextField.isEnabled = enabled - productIDTextField.isEnabled = enabled - productVersionTextField.isEnabled = enabled + var posibleValues: [String] { + switch self { + case .vendorIdSource: + return [VendorIDSource.fromAssignedNumbersDocument.rawValue.description, + VendorIDSource.fromVendorIDValue.rawValue.description] + + default: + return [] + } + } - vendorIDSourceTextField.text = "\(value.vendorIdSource.rawValue)" - vendorIDTextField.text = "\(value.vendorId)" - productIDTextField.text = "\(value.productId)" - productVersionTextField.text = "\(value.productVersion)" + var keyboardType: UIKeyboardType { + switch self { + case .vendorIdSource: + return .default + + default: + return.numberPad + } + } } } diff --git a/BluetoothExplorer/PnPIDCharacteristic.storyboard b/BluetoothExplorer/PnPIDCharacteristic.storyboard index 6be3428..44da6e9 100644 --- a/BluetoothExplorer/PnPIDCharacteristic.storyboard +++ b/BluetoothExplorer/PnPIDCharacteristic.storyboard @@ -1,104 +1,31 @@ - + - - + - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - + diff --git a/BluetoothExplorer/View/InputTextField.swift b/BluetoothExplorer/View/InputTextField.swift index 899b96f..c5910e5 100644 --- a/BluetoothExplorer/View/InputTextField.swift +++ b/BluetoothExplorer/View/InputTextField.swift @@ -11,6 +11,22 @@ import UIKit class InputTextField: UITextField { + // MARK: - Properties + + var posibleValues = [String]() { + didSet { + inputView = (posibleValues.count == 0) ? nil : pickerView + } + } + + private lazy var pickerView: UIPickerView = { + let picker = UIPickerView() + picker.delegate = self + return picker + }() + + // MARK: - Initializers + override init(frame: CGRect) { super.init(frame: frame) addToolbar() @@ -21,7 +37,9 @@ class InputTextField: UITextField { addToolbar() } - func addToolbar() { + // MARK: - Methods + + private func addToolbar() { let toolbar = UIToolbar() toolbar.isTranslucent = true @@ -41,3 +59,31 @@ class InputTextField: UITextField { } } + +extension InputTextField: UIPickerViewDataSource { + + func numberOfComponents(in pickerView: UIPickerView) -> Int { + + return 1 + } + + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + + return posibleValues.count + } + +} + +extension InputTextField: UIPickerViewDelegate { + + func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + + return posibleValues[row] + } + + func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + + text = posibleValues[row] + } + +} diff --git a/BluetoothExplorer/View/InputTextView.swift b/BluetoothExplorer/View/InputTextView.swift index 4594627..66f9e77 100644 --- a/BluetoothExplorer/View/InputTextView.swift +++ b/BluetoothExplorer/View/InputTextView.swift @@ -53,6 +53,12 @@ class InputTextView: NibDesignableView { set { textField.isEnabled = newValue } } + public var posibleInputValues: [String] { + + get { return textField.posibleValues } + set { textField.posibleValues = newValue; } + } + private var validation: Validation = .none { didSet { updateView() } }