Beginning stages of swiftification.
This commit is contained in:
parent
52119f7b31
commit
4915bda4b9
@ -18,6 +18,7 @@
|
||||
01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; };
|
||||
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
||||
0A41BA7F23453A6400D4C0BC /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextField.swift */; };
|
||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; };
|
||||
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
|
||||
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; };
|
||||
@ -203,6 +204,7 @@
|
||||
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
|
||||
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
|
||||
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
||||
0A41BA7E23453A6400D4C0BC /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||
948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = "<group>"; };
|
||||
B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
|
||||
B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = "<group>"; };
|
||||
@ -740,6 +742,7 @@
|
||||
D29DF24321E6A176003B2FB9 /* MFDigitTextField.h */,
|
||||
D29DF24821E6A177003B2FB9 /* MFDigitTextField.m */,
|
||||
D29DF24A21E6A177003B2FB9 /* MFDigitTextField.xib */,
|
||||
0A41BA7E23453A6400D4C0BC /* TextField.swift */,
|
||||
);
|
||||
path = TextFields;
|
||||
sourceTree = "<group>";
|
||||
@ -1046,6 +1049,7 @@
|
||||
D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */,
|
||||
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
|
||||
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
|
||||
0A41BA7F23453A6400D4C0BC /* TextField.swift in Sources */,
|
||||
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */,
|
||||
D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */,
|
||||
D29DF17A21E69E1F003B2FB9 /* MFCustomButton.m in Sources */,
|
||||
|
||||
618
MVMCoreUI/Atoms/TextFields/TextField.swift
Normal file
618
MVMCoreUI/Atoms/TextFields/TextField.swift
Normal file
@ -0,0 +1,618 @@
|
||||
//
|
||||
// TextField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 10/2/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import MVMCoreUI
|
||||
import UIKit
|
||||
|
||||
@objc protocol MFTextFieldDelegate: NSObjectProtocol {
|
||||
// Called when the entered text becomes valid based on the validation block
|
||||
@objc optional func entryIsValid(_ textfield: MFTextField?)
|
||||
// Called when the entered text becomes invalid based on the validation block
|
||||
@objc optional func entryIsInvalid(_ textfield: MFTextField?)
|
||||
// Dismisses the keyboard.
|
||||
@objc optional func dismissFieldInput(_ sender: Any?)
|
||||
}
|
||||
|
||||
class MFTextField: ViewConstrainingView, MVMCoreUIMoleculeViewProtocol, FormValidationProtocol {
|
||||
weak var view: UIView?
|
||||
@IBOutlet weak var textFieldContainerView: UIView?
|
||||
@IBOutlet weak var backgroundView: UIView?
|
||||
@IBOutlet weak var textField: UITextField?
|
||||
@IBOutlet weak var formLabel: Label?
|
||||
@IBOutlet weak var separatorView: UIView?
|
||||
/*make it public so outsider class can know the posistion of it. */ @IBOutlet weak var heightConstraint: NSLayoutConstraint?
|
||||
@IBOutlet weak var formLabelRightPin: NSLayoutConstraint?
|
||||
var enabled = false
|
||||
// To set the placeholder and text
|
||||
weak var text: String?
|
||||
weak var formText: String?
|
||||
weak var fieldKey: String?
|
||||
weak var placeholder: String?
|
||||
/* will move out in Feb release */ var hideBorder = false
|
||||
|
||||
weak var datePicker: UIDatePicker?
|
||||
private(set) weak var toolbar: UIToolbar?
|
||||
//helper
|
||||
var formatter: DateFormatter?
|
||||
// If you're using a MFViewController, you must set this to it
|
||||
weak var uiTextFieldDelegate: UITextFieldDelegate?
|
||||
// The delegate and block for validation. Validates if the text that the user has entered is valid or not. Checked after each change if there is a delegate.
|
||||
weak var mfTextFieldDelegate: MFTextFieldDelegate?
|
||||
var valid = false
|
||||
var validationBlock: ((_ enteredValue: String?) -> Bool)?
|
||||
// custom text colors
|
||||
var customEnabledTextColor: UIColor?
|
||||
var customDisabledTextColor: UIColor?
|
||||
//default error message
|
||||
var errMessage: String?
|
||||
var editCompleteAction: ((_ text: String?) -> Void)?
|
||||
|
||||
|
||||
private var customPlaceHolderColor: UIColor?
|
||||
@IBOutlet private weak var separatorHeightConstraint: NSLayoutConstraint!
|
||||
private var borderPath: UIBezierPath?
|
||||
private var calendar: Calendar?
|
||||
@IBOutlet private weak var textContainerLeftPin: NSLayoutConstraint!
|
||||
@IBOutlet private weak var errorLableLeftPin: NSLayoutConstraint!
|
||||
@IBOutlet private weak var formLabelLeftPin: NSLayoutConstraint!
|
||||
@IBOutlet private weak var textContainerRightPin: NSLayoutConstraint!
|
||||
@IBOutlet private weak var errorLableRightPin: NSLayoutConstraint!
|
||||
|
||||
// MARK: - setup
|
||||
func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
self.formLabel.updateView(size)
|
||||
self.label.font = MFStyler.fontForTextFieldUnderLabel()
|
||||
MFStyler.styleTextField(self.textField)
|
||||
self.dashLine.updateView(size)
|
||||
})
|
||||
}
|
||||
|
||||
func setupView() {
|
||||
if !self.view {
|
||||
backgroundColor = UIColor.clear
|
||||
let nib = getNib()
|
||||
let views = nib?.instantiate(withOwner: self, options: nil)
|
||||
let view = views?.first as? UIView
|
||||
view?.translatesAutoresizingMaskIntoConstraints = false
|
||||
view?.setContentHuggingPriority(.required, for: .vertical)
|
||||
view?.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
self.view = view
|
||||
view?.frame = frame
|
||||
if let view = view {
|
||||
addSubview(view)
|
||||
}
|
||||
pinView(toSuperView: view)
|
||||
|
||||
textField.font = MFStyler.fontForTextField()
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
formLabel.font = MFStyler.fontB3()
|
||||
formLabel.textColor = UIColor.mfBattleshipGrey()
|
||||
|
||||
label.font = MFStyler.fontForTextFieldUnderLabel()
|
||||
label.textColor = UIColor.black
|
||||
|
||||
dropDownCarrotLabel.hidden = true
|
||||
separatorView.backgroundColor = UIColor.black
|
||||
dashLine.backgroundColor = UIColor.white
|
||||
dashLine.hidden = true
|
||||
MFStyler.styleTextField(textField)
|
||||
|
||||
dropDownCarrotLabel.isUserInteractionEnabled = true
|
||||
let tapOnCarrot = UITapGestureRecognizer(target: self, action: #selector(startEditing))
|
||||
dropDownCarrotLabel.addGestureRecognizer(tapOnCarrot)
|
||||
enabled = true
|
||||
|
||||
// Disable SmartQuotes
|
||||
if #available(iOS 11.0, *) {
|
||||
textField.smartQuotesType = .no
|
||||
textField.smartDashesType = .no
|
||||
textField.smartInsertDeleteType = .no
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getNib() -> UINib? {
|
||||
return UINib(nibName: NSStringFromClass(type(of: self).self), bundle: MVMCoreUIUtility.bundleForMVMCoreUI())
|
||||
}
|
||||
|
||||
class func mfTextField() -> Self? {
|
||||
let view = self.init()
|
||||
view?.hasDropDown = false
|
||||
return view
|
||||
}
|
||||
|
||||
class func mfTextField(withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) -> Self? {
|
||||
let textField = self.mfTextField()
|
||||
textField?.bothTextFieldDelegates = delegate
|
||||
return textField
|
||||
}
|
||||
|
||||
class func mfTextField(withMap map: [AnyHashable : Any]?, bothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) -> Self? {
|
||||
let textField = self.mfTextField()
|
||||
textField?.translatesAutoresizingMaskIntoConstraints = false
|
||||
textField?.setWithMap(map, bothDelegates: delegate)
|
||||
return textField
|
||||
}
|
||||
|
||||
class func mfTextFieldForDropDown() -> Self? {
|
||||
let textField = self.mfTextField()
|
||||
textField?.dropDownCarrotLabel().hidden = false
|
||||
textField?.hasDropDown = true
|
||||
return textField
|
||||
}
|
||||
|
||||
class func mfTextFieldForDropDown(withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) -> Self? {
|
||||
let textField = self.mfTextFieldForDropDown()
|
||||
textField?.bothTextFieldDelegates = delegate
|
||||
return textField
|
||||
}
|
||||
|
||||
// MARK: - Utilities
|
||||
func createDatePicker() {
|
||||
//tool bar
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: textField.delegate)
|
||||
|
||||
//date picker
|
||||
datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField)
|
||||
|
||||
let calendar = Calendar.current
|
||||
calendar.timeZone = NSTimeZone.system
|
||||
self.calendar = calendar
|
||||
}
|
||||
|
||||
func inputFromDatePicker(from fromDate: Date?, to toDate: Date?, showFromDateAsDefaultInput show: Bool) {
|
||||
createDatePicker()
|
||||
if show {
|
||||
if let fromDate = fromDate {
|
||||
if calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
self.text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
datePicker.minimumDate = fromDate
|
||||
datePicker.maximumDate = toDate
|
||||
}
|
||||
|
||||
func setDatePickerFrom(_ fromDate: Date?, to toDate: Date?) {
|
||||
if let fromDate = fromDate {
|
||||
if calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
self.text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
datePicker.minimumDate = fromDate
|
||||
datePicker.maximumDate = toDate
|
||||
datePicker.timeZone = NSTimeZone.system
|
||||
}
|
||||
|
||||
func dismissDatePicker() -> Date? {
|
||||
let pickedDate = datePicker.date
|
||||
if let pickedDate = pickedDate {
|
||||
if calendar.isDate(pickedDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
self.text = formatter.string(from: pickedDate)
|
||||
}
|
||||
}
|
||||
textField.resignFirstResponder()
|
||||
return pickedDate
|
||||
}
|
||||
|
||||
func dismissPicker() {
|
||||
textField.resignFirstResponder()
|
||||
}
|
||||
|
||||
func setErrorMessage(_ errorMessage: String?) {
|
||||
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
if self.enabled == true {
|
||||
self.separatorHeightConstraint.constant = 4
|
||||
self.errorShowing = true
|
||||
self.separatorView.backgroundColor = UIColor.mfPumpkin()
|
||||
self.label.text() = errorMessage
|
||||
self.label.numberOfLines = 0
|
||||
self.textField.accessibilityValue() = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message"), self.textField.text() ?? "", errorMessage ?? "")
|
||||
self.setNeedsDisplay()
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func pushAccessibilityNotification() {
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
UIAccessibilityPostNotification(UIAccessibility.Notification.layoutChanged, self.textField)
|
||||
})
|
||||
}
|
||||
|
||||
func hideError() {
|
||||
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
self.separatorHeightConstraint.constant = 1
|
||||
self.separatorView.backgroundColor = UIColor.black
|
||||
self.layoutIfNeeded()
|
||||
self.errorShowing = false
|
||||
self.label.textColor = UIColor.black
|
||||
self.label.text() = ""
|
||||
self.textField.accessibilityValue() = nil
|
||||
self.setNeedsDisplay()
|
||||
self.layoutIfNeeded()
|
||||
})
|
||||
}
|
||||
|
||||
func placeholder() -> String? {
|
||||
return textField.attributedPlaceholder.string
|
||||
}
|
||||
|
||||
func text() -> String? {
|
||||
return textField.text()
|
||||
}
|
||||
|
||||
// MARK: - Setters
|
||||
|
||||
func setPlaceholder(_ placeholder: String?, with color: UIColor?) {
|
||||
customPlaceHolderColor = color
|
||||
// fixed crash issue
|
||||
if placeholder != nil {
|
||||
if let color = color {
|
||||
textField.attributedPlaceholder = NSAttributedString(string: placeholder ?? "", attributes: [
|
||||
NSAttributedString.Key.foregroundColor: color
|
||||
])
|
||||
}
|
||||
}
|
||||
if textField.text.length > 0 && !errorShowing {
|
||||
label.text = placeholder
|
||||
} else if !errorShowing {
|
||||
label.text = ""
|
||||
}
|
||||
setAccessibilityString(placeholder)
|
||||
}
|
||||
|
||||
func setAccessibilityString(_ accessibilityString: String?) {
|
||||
var accessibilityString = accessibilityString
|
||||
// adding missing accessibilityLabel value
|
||||
// if we have some value in accessibilityLabel,
|
||||
// then only can append regular and picker item
|
||||
if hasDropDown {
|
||||
// MFDLog(@"Label: %@", self.textField.accessibilityLabel);
|
||||
accessibilityString = accessibilityString ?? "" + (MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item"))
|
||||
// MFDLog(@"Label: %@", self.textField.accessibilityLabel);
|
||||
} else {
|
||||
accessibilityString = accessibilityString ?? "" + (MVMCoreUIUtility.hardcodedString(withKey: "textfield_regular"))
|
||||
// MFDLog(@"Label: %@", self.textField.accessibilityLabel);
|
||||
}
|
||||
|
||||
textField.accessibilityLabel() = "\(accessibilityString ?? "") \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state"))"
|
||||
}
|
||||
|
||||
func setFormText(_ formText: String?) {
|
||||
formLabel.text = formText
|
||||
setAccessibilityString(formText)
|
||||
}
|
||||
|
||||
func setPlaceholder(_ placeholder: String?) {
|
||||
setPlaceholder(placeholder, with: customPlaceHolderColor ?? UIColor.black)
|
||||
}
|
||||
|
||||
func setText(_ text: String?) {
|
||||
textField.text = text
|
||||
valueChanged()
|
||||
}
|
||||
|
||||
func setMfTextFieldDelegate(_ mfTextFieldDelegate: MFTextFieldDelegate?) {
|
||||
self.mfTextFieldDelegate = mfTextFieldDelegate
|
||||
if mfTextFieldDelegate != nil && !observingForChanges {
|
||||
observingForChanges = true
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextField.textDidChangeNotification, object: textField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextField.textDidEndEditingNotification, object: textField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextField.textDidBeginEditingNotification, object: textField)
|
||||
} else if mfTextFieldDelegate == nil && observingForChanges {
|
||||
observingForChanges = false
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidChangeNotification, object: textField)
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidEndEditingNotification, object: textField)
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidBeginEditingNotification, object: textField)
|
||||
}
|
||||
}
|
||||
|
||||
func setUiTextFieldDelegate(_ uiTextFieldDelegate: UITextFieldDelegate?) {
|
||||
self.uiTextFieldDelegate = uiTextFieldDelegate
|
||||
textField.delegate = uiTextFieldDelegate
|
||||
}
|
||||
|
||||
func setBothTextFieldDelegates(_ delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
||||
mfTextFieldDelegate = delegate
|
||||
uiTextFieldDelegate = delegate
|
||||
}
|
||||
|
||||
func setWithMap(_ map: [AnyHashable : Any]?) {
|
||||
if map?.count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var string = map?.string(KeyLabel)
|
||||
if (string?.count ?? 0) > 0 {
|
||||
formText = string
|
||||
}
|
||||
string = map?.string(KeyValue)
|
||||
if (string?.count ?? 0) > 0 {
|
||||
text = string
|
||||
}
|
||||
string = map?.string(forKey: KeyDisable)
|
||||
if string?.isEqual(StringY) ?? false || map?.bool(forKey: KeyDisable) != nil {
|
||||
enable(false)
|
||||
}
|
||||
string = map?.string(KeyErrorMessage)
|
||||
if (string?.count ?? 0) > 0 {
|
||||
errMessage = string
|
||||
}
|
||||
|
||||
// key used to send text value to server
|
||||
string = map?.string(KeyFieldKey)
|
||||
if (string?.count ?? 0) > 0 {
|
||||
fieldKey = string
|
||||
}
|
||||
|
||||
string = map?.string(KeyType)
|
||||
if (string == "dropDown") {
|
||||
dropDownCarrotLabel().hidden = false
|
||||
self.hasDropDown = true
|
||||
} else if (string == "password") {
|
||||
textField.isSecureTextEntry = true
|
||||
} else if (string == "number") {
|
||||
textField.keyboardType = .numberPad
|
||||
} else if (string == "email") {
|
||||
textField.keyboardType = .emailAddress
|
||||
}
|
||||
|
||||
string = map?.string("regex")
|
||||
if (string?.count ?? 0) != 0 {
|
||||
validationBlock = { enteredValue in
|
||||
return MVMCoreUIUtility.validate(enteredValue, withRegularExpression: string)
|
||||
}
|
||||
} else {
|
||||
setDefaultValidationBlock()
|
||||
}
|
||||
}
|
||||
|
||||
func setWithMap(_ map: [AnyHashable : Any]?, bothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegate)
|
||||
self.bothTextFieldDelegates = delegate
|
||||
setWithMap(map)
|
||||
}
|
||||
|
||||
func setValidationBlock(_ validationBlock: @escaping (String?) -> Bool) {
|
||||
self.validationBlock = validationBlock
|
||||
valueChanged()
|
||||
}
|
||||
|
||||
func setDefaultValidationBlock() {
|
||||
self.validationBlock = { enteredValue in
|
||||
if (enteredValue?.count ?? 0) > 0 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setLeftPinConstant(_ constant: CGFloat) {
|
||||
textContainerLeftPin.constant = constant
|
||||
errorLableLeftPin.constant = constant
|
||||
formLabelLeftPin.constant = constant
|
||||
}
|
||||
|
||||
func setRightPinConstant(_ constant: CGFloat) {
|
||||
textContainerRightPin.constant = constant
|
||||
errorLableRightPin.constant = constant
|
||||
formLabelRightPin.constant = constant
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.bothTextFieldDelegates = nil
|
||||
}
|
||||
|
||||
// MARK: - XIB Helpers
|
||||
func showDropDown(_ show: Bool) {
|
||||
if hasDropDown {
|
||||
dropDownCarrotLabel.hidden = !show
|
||||
dropDownCarrotWidth.active = !show
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
func enable(_ enable: Bool) {
|
||||
enabled = enable //Set outside the dispatch so that registerAnimations can know about it
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
self.isUserInteractionEnabled = enable
|
||||
self.textField.userInteractionEnabled = enable
|
||||
self.textField.isEnabled = enable
|
||||
if enable {
|
||||
self.textField.textColor = self.customEnabledTextColor ?? UIColor.black
|
||||
self.formLabel.textColor = UIColor.mfBattleshipGrey()
|
||||
self.label.textColor = UIColor.black
|
||||
if self.errorShowing {
|
||||
self.separatorView.backgroundColor = UIColor.mfPumpkin()
|
||||
} else {
|
||||
self.separatorView.backgroundColor = UIColor.black
|
||||
}
|
||||
self.showDropDown(true)
|
||||
} else {
|
||||
self.textField.textColor = self.customDisabledTextColor ?? UIColor.mfSilver()
|
||||
self.formLabel.textColor = UIColor.mfSilver()
|
||||
self.label.textColor = UIColor.mfSilver()
|
||||
self.showDropDown(false)
|
||||
self.hideError() //should not have error if the field is disabled
|
||||
self.separatorView.backgroundColor = UIColor.mfSilver()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func showLabel(_ show: Bool) {
|
||||
label.hidden = !show
|
||||
}
|
||||
|
||||
func dashSeperatorView(_ dash: Bool) {
|
||||
if dash {
|
||||
dashLine.hidden = false
|
||||
//never hide seperator view because it could be possiblely used by other classes for positioning
|
||||
separatorView.backgroundColor = UIColor.clear
|
||||
} else {
|
||||
dashLine.hidden = true
|
||||
separatorView.backgroundColor = UIColor.black
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Observing for change
|
||||
func validateBlock() {
|
||||
valueChanged()
|
||||
}
|
||||
|
||||
func valueChanged() {
|
||||
|
||||
// update label for placeholder
|
||||
if !errorShowing {
|
||||
label.text = ""
|
||||
}
|
||||
|
||||
// Check validity.
|
||||
let previousValidity = valid
|
||||
if validationBlock {
|
||||
valid = validationBlock(text)
|
||||
} else {
|
||||
//if validation not set, input will always be valid
|
||||
valid = true
|
||||
}
|
||||
|
||||
if previousValidity && !valid {
|
||||
if errMessage {
|
||||
self.errorMessage = errMessage
|
||||
}
|
||||
if mfTextFieldDelegate.responds(to: #selector(entryIsInvalid(_:))) {
|
||||
mfTextFieldDelegate.entryIsInvalid(self)
|
||||
}
|
||||
} else if !previousValidity && valid {
|
||||
hideError()
|
||||
if mfTextFieldDelegate.responds(to: #selector(entryIsValid(_:))) {
|
||||
mfTextFieldDelegate.entryIsValid(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func endInputing() {
|
||||
if isValid {
|
||||
hideError()
|
||||
separatorView.backgroundColor = UIColor.black
|
||||
} else {
|
||||
if errMessage {
|
||||
self.errorMessage = errMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - helper
|
||||
|
||||
func startEditing() {
|
||||
textField.becomeFirstResponder()
|
||||
if !errorShowing {
|
||||
separatorView.backgroundColor = UIColor.black
|
||||
separatorHeightConstraint.constant = 1
|
||||
}
|
||||
}
|
||||
|
||||
class func getEnabledTextfields(_ textFieldToDetermine: [MFTextField]?) -> [AnyHashable]? {
|
||||
var enabledTextFields: [AnyHashable] = []
|
||||
for textfield in textFieldToDetermine ?? [] {
|
||||
if textfield.isEnabled {
|
||||
enabledTextFields.append(textfield)
|
||||
}
|
||||
}
|
||||
return enabledTextFields
|
||||
}
|
||||
|
||||
//#pragma mark - Accessibility
|
||||
|
||||
|
||||
func formatter() -> DateFormatter? {
|
||||
if !formatter {
|
||||
formatter = DateFormatter()
|
||||
formatter.dateStyle = .medium
|
||||
formatter.timeZone = NSTimeZone.system
|
||||
formatter.locale = NSLocale.current
|
||||
formatter.formatterBehavior = .default
|
||||
}
|
||||
return formatter
|
||||
}
|
||||
|
||||
func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
borderPath.removeAllPoints()
|
||||
if !hideBorder {
|
||||
let frame = textFieldContainerView.frame
|
||||
borderPath = UIBezierPath()
|
||||
borderPath.move(to: CGPoint(x: frame.origin.x, y: frame.origin.y + frame.size.height))
|
||||
borderPath.addLine(to: CGPoint(x: frame.origin.x, y: frame.origin.y))
|
||||
borderPath.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y))
|
||||
borderPath.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y + frame.size.height))
|
||||
|
||||
borderPath.lineWidth = 1
|
||||
|
||||
var strokeColor: UIColor?
|
||||
if errorShowing {
|
||||
strokeColor = UIColor.mfPumpkin()
|
||||
} else {
|
||||
strokeColor = UIColor.mfSilver()
|
||||
}
|
||||
|
||||
strokeColor?.setStroke()
|
||||
|
||||
borderPath.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
#pragma mark - MVMCoreUIMoleculeViewProtocol
|
||||
|
||||
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||
if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) {
|
||||
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
|
||||
FormValidator *formValidator = [FormValidator getFormValidatorForDelegate:delegateObject.formValidationProtocol];
|
||||
|
||||
[self setWithMap:json];
|
||||
self.mfTextFieldDelegate = formValidator;
|
||||
self.uiTextFieldDelegate = delegateObject.uiTextFieldDelegate;
|
||||
[MVMCoreUICommonViewsUtility addDismissToolbar:self.textField delegate:self.uiTextFieldDelegate];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
||||
return 76;
|
||||
}
|
||||
|
||||
#pragma mark - FormValidationProtocol
|
||||
|
||||
|
||||
- (BOOL)isValidField {
|
||||
return self.isValid;
|
||||
}
|
||||
|
||||
- (nullable NSString *)formFieldName {
|
||||
return self.fieldKey;
|
||||
}
|
||||
|
||||
- (nullable id)formFieldValue {
|
||||
return self.text;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user