184 lines
5.7 KiB
Swift
184 lines
5.7 KiB
Swift
//
|
|
// SingleValueViewController.swift
|
|
// Live Link VCAM
|
|
//
|
|
// Created by Brian Smith on 12/31/19.
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
//
|
|
|
|
//
|
|
// The SingleValueViewController allows either the entry of a single value
|
|
// OR the editing of a value with an optional Delete button.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
class SingleValueViewController : UITableViewController {
|
|
|
|
enum Mode {
|
|
case create
|
|
case edit
|
|
case editWithDelete
|
|
}
|
|
|
|
enum ActionType {
|
|
case done
|
|
case cancel
|
|
case delete
|
|
}
|
|
|
|
enum AllowedType {
|
|
case any
|
|
case ipAddress
|
|
case integer
|
|
case unreal // alphanumeric, _, -
|
|
}
|
|
|
|
|
|
@IBOutlet weak var textField: UITextField!
|
|
var doneButton: UIBarButtonItem?
|
|
var cancelButton: UIBarButtonItem?
|
|
|
|
var mode = Mode.create
|
|
var allowedType = AllowedType.any
|
|
var initialValue = String()
|
|
var placeholderValue : String?
|
|
var deleteLabelText : String?
|
|
var finished : ((ActionType, String?) -> Void)? = nil
|
|
|
|
private var isRoot = false
|
|
public private(set) var finishedAction = ActionType.cancel
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
self.doneButton = UIBarButtonItem(title: mode == .create ? Localized.buttonAdd() : Localized.buttonDone(), style: .done, target: self, action: #selector(action))
|
|
|
|
// if this view is the root view of a nagivation controller, then we add a "cancel" and "done" button.
|
|
if self == self.navigationController?.viewControllers.first {
|
|
isRoot = true
|
|
self.cancelButton = UIBarButtonItem(title: Localized.buttonCancel(), style: .plain, target: self, action: #selector(action))
|
|
|
|
self.navigationItem.leftBarButtonItem = self.cancelButton
|
|
self.navigationItem.rightBarButtonItem = self.doneButton
|
|
} else {
|
|
|
|
if UIDevice.current.userInterfaceIdiom == .phone {
|
|
self.navigationItem.rightBarButtonItem = self.doneButton
|
|
}
|
|
|
|
// else the finishedAction is set to done always : this means that any dismissal (probably via
|
|
// a back gesture) of the VC is essentially a done/confirm
|
|
finishedAction = .done
|
|
}
|
|
|
|
self.textField.text = initialValue
|
|
self.textField.placeholder = self.placeholderValue
|
|
self.textField.delegate = self
|
|
|
|
switch allowedType {
|
|
case .integer:
|
|
self.textField.keyboardType = .numberPad
|
|
case .ipAddress:
|
|
self.textField.keyboardType = .numbersAndPunctuation
|
|
default:
|
|
break
|
|
}
|
|
|
|
}
|
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
super.viewWillAppear(animated)
|
|
|
|
if #available(iOS 13.0, *) {
|
|
navigationController?.navigationBar.setNeedsLayout()
|
|
}
|
|
}
|
|
|
|
override func viewDidAppear(_ animated: Bool) {
|
|
super.viewDidAppear(animated)
|
|
|
|
self.textField.becomeFirstResponder()
|
|
}
|
|
|
|
override func viewWillDisappear(_ animated: Bool) {
|
|
|
|
if let callback = finished {
|
|
callback(finishedAction, self.textField.text)
|
|
}
|
|
|
|
super.viewWillDisappear(animated)
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
if indexPath.section == 1 {
|
|
self.textField.text = nil
|
|
self.finishedAction = .delete
|
|
|
|
if isRoot {
|
|
self.dismiss(animated: true, completion: nil)
|
|
} else {
|
|
self.navigationController?.popViewController(animated: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
|
|
|
// override the "delete" label if there was one specified
|
|
if indexPath.section == 1 {
|
|
if let text = deleteLabelText {
|
|
cell.textLabel?.text = text
|
|
}
|
|
}
|
|
}
|
|
|
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
|
if mode != .editWithDelete {
|
|
return 1
|
|
} else {
|
|
return super.numberOfSections(in: tableView)
|
|
}
|
|
}
|
|
|
|
@IBAction func action(sender : UIBarButtonItem) {
|
|
|
|
if sender == self.doneButton {
|
|
self.finishedAction = .done
|
|
}
|
|
|
|
// this action can only occur on a modal dialog
|
|
self.dismiss(animated: true, completion: nil)
|
|
}
|
|
|
|
func handleTextField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
|
|
|
if textField == self.textField {
|
|
|
|
switch allowedType {
|
|
case .integer:
|
|
let allowedCharacters = CharacterSet(charactersIn: "0123456789")
|
|
return allowedCharacters.isSuperset(of: CharacterSet(charactersIn: string))
|
|
case .ipAddress:
|
|
let allowedCharacters = CharacterSet(charactersIn: "0123456789.")
|
|
return allowedCharacters.isSuperset(of: CharacterSet(charactersIn: string))
|
|
case .unreal:
|
|
let allowedCharacters = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-_"))
|
|
return allowedCharacters.isSuperset(of: CharacterSet(charactersIn: string))
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
}
|
|
|
|
extension SingleValueViewController : UITextFieldDelegate {
|
|
|
|
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
|
return handleTextField(textField, shouldChangeCharactersIn: range, replacementString: string)
|
|
}
|
|
}
|