Reworked bezier logic for CaretView. It was not optimal.
This commit is contained in:
parent
5e96653d4b
commit
475d08296b
@ -25,8 +25,6 @@ import UIKit
|
|||||||
return layer
|
return layer
|
||||||
}()
|
}()
|
||||||
|
|
||||||
weak var textBoxDelegate: DigitBoxDelegate?
|
|
||||||
|
|
||||||
private var previousSize: CGFloat = 0.0
|
private var previousSize: CGFloat = 0.0
|
||||||
|
|
||||||
/// Determines if a border should be drawn.
|
/// Determines if a border should be drawn.
|
||||||
@ -36,6 +34,12 @@ import UIKit
|
|||||||
private var borderStrokeColor: UIColor = .mfSilver()
|
private var borderStrokeColor: UIColor = .mfSilver()
|
||||||
private var borderPath: UIBezierPath = UIBezierPath()
|
private var borderPath: UIBezierPath = UIBezierPath()
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Delegate
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
weak var textBoxDelegate: DigitBoxDelegate?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Constraints
|
// MARK: - Constraints
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -47,11 +51,6 @@ import UIKit
|
|||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
fatalError("DigitBox has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
public override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
setup()
|
setup()
|
||||||
@ -61,11 +60,16 @@ import UIKit
|
|||||||
self.init(frame: .zero)
|
self.init(frame: .zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required public init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
fatalError("DigitBox has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
func setup() {
|
private func setup() {
|
||||||
|
|
||||||
guard constraints.isEmpty else { return }
|
guard constraints.isEmpty else { return }
|
||||||
|
|
||||||
@ -74,7 +78,7 @@ import UIKit
|
|||||||
textAlignment = .center
|
textAlignment = .center
|
||||||
keyboardType = .numberPad
|
keyboardType = .numberPad
|
||||||
layer.borderWidth = 1
|
layer.borderWidth = 1
|
||||||
showError(false)
|
showErrorState(false)
|
||||||
|
|
||||||
widthConstraint = widthAnchor.constraint(equalToConstant: 39)
|
widthConstraint = widthAnchor.constraint(equalToConstant: 39)
|
||||||
widthConstraint?.isActive = true
|
widthConstraint?.isActive = true
|
||||||
@ -83,7 +87,6 @@ import UIKit
|
|||||||
heightConstraint?.isActive = true
|
heightConstraint?.isActive = true
|
||||||
|
|
||||||
layer.addSublayer(bottomBar)
|
layer.addSublayer(bottomBar)
|
||||||
|
|
||||||
updateView(MVMCoreUISplitViewController.getDetailViewWidth())
|
updateView(MVMCoreUISplitViewController.getDetailViewWidth())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +164,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showError(_ show: Bool) {
|
func showErrorState(_ show: Bool) {
|
||||||
|
|
||||||
showError = show
|
showError = show
|
||||||
borderStrokeColor = show ? .mfPumpkin() : .mfSilver()
|
borderStrokeColor = show ? .mfPumpkin() : .mfSilver()
|
||||||
|
|||||||
@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass of TextEntryField due to the conveniences provided.
|
||||||
|
* TODO: Compare overrides to determine if TextEntryField is necessary.
|
||||||
|
*/
|
||||||
@objcMembers open class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
@objcMembers open class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
@ -20,69 +23,65 @@ import UIKit
|
|||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
private var numberOfDigits = 0
|
private var numberOfDigits = 4
|
||||||
private var switchedAutomatically = false
|
private var switchedAutomatically = false
|
||||||
public var digitFields: [DigitBox]?
|
public var digitFields: [DigitBox] = []
|
||||||
|
|
||||||
public override var isEnabled: Bool {
|
public override var isEnabled: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
if isEnabled {
|
if isEnabled {
|
||||||
titleLabel.styleB2(true)
|
titleLabel.styleB2(true)
|
||||||
} else {
|
} else {
|
||||||
titleLabel.textColor = UIColor.mfBattleshipGrey()
|
titleLabel.textColor = .mfBattleshipGrey()
|
||||||
}
|
}
|
||||||
|
|
||||||
for textField in digitFields ?? [] {
|
for textField in digitFields {
|
||||||
textField.isUserInteractionEnabled = isEnabled
|
textField.isUserInteractionEnabled = isEnabled
|
||||||
textField.isEnabled = isEnabled
|
textField.isEnabled = isEnabled
|
||||||
textField.textColor = isEnabled ? .black : UIColor.mfBattleshipGrey()
|
textField.textColor = isEnabled ? .black : .mfBattleshipGrey()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets placeholder text in the textField.
|
/// Sets placeholder text in the textField.
|
||||||
public override var feedback: String? {
|
public override var placeholder: String? {
|
||||||
get {
|
get {
|
||||||
var string = ""
|
var string = ""
|
||||||
|
|
||||||
for digitField in digitFields ?? [] {
|
digitFields.forEach { string += $0.attributedPlaceholder?.string ?? "" }
|
||||||
if let digitext = digitField.attributedPlaceholder?.string {
|
|
||||||
string += digitext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !string.isEmpty ? string : nil
|
return !string.isEmpty ? string : nil
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
guard let fieldValue = newValue, let fields = digitFields else { return }
|
guard let newValue = newValue else { return }
|
||||||
|
|
||||||
for (index, field) in fields.enumerated() {
|
for (index, field) in digitFields.enumerated() {
|
||||||
if index < fieldValue.count {
|
if index < newValue.count {
|
||||||
let stringForIndex = (newValue as NSString?)?.substring(with: NSRange(location: index, length: 1))
|
let indexChar = newValue.index(newValue.startIndex, offsetBy: index)
|
||||||
field.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [
|
field.attributedPlaceholder = NSAttributedString(string: String(newValue[indexChar]), attributes: [
|
||||||
NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()])
|
NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// if feedback.text.length > 0 {
|
|
||||||
// labelToTextFieldPin?.constant = 10
|
|
||||||
// } else {
|
|
||||||
// labelToTextFieldPin?.constant = 0
|
|
||||||
// }
|
|
||||||
|
|
||||||
// adding missing accessibilityLabel value
|
// If there is already text in the textfield, set the place holder label below.
|
||||||
// if we have some value in accessibilityLabel,
|
if let text = text, !text.isEmpty && !showError {
|
||||||
// then only can append regular and picker item
|
feedback = placeholder
|
||||||
// textField.accessibilityLabel() = newValue ?? "" + (MVMCoreUIUtility.hardcodedString(withKey: "mfdigittextfield_regular"))
|
} else if !showError {
|
||||||
//
|
feedback = ""
|
||||||
// super.showErrorMessage(errorMessage)
|
}
|
||||||
//
|
|
||||||
// if self.showErrorMessage {
|
if let feedback = feedback, !feedback.isEmpty {
|
||||||
// self.labelToTextFieldPin?.constant = 10
|
feedbackContainerDistance?.constant = 10
|
||||||
// }
|
} else {
|
||||||
// for field in self.digitFields ?? [] {
|
feedbackContainerDistance?.constant = 0
|
||||||
// field.setAsError()
|
}
|
||||||
// }
|
|
||||||
|
/*
|
||||||
|
* adding missing accessibilityLabel value
|
||||||
|
* if we have some value in accessibilityLabel,
|
||||||
|
* then only can append regular and picker item
|
||||||
|
*/
|
||||||
|
textField.accessibilityLabel = newValue + (MVMCoreUIUtility.hardcodedString(withKey: "mfdigittextfield_regular") ?? "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,21 +89,17 @@ import UIKit
|
|||||||
get {
|
get {
|
||||||
var string = ""
|
var string = ""
|
||||||
|
|
||||||
for digitField in digitFields ?? [] {
|
digitFields.forEach { string += $0.text ?? "" }
|
||||||
if let digitText = digitField.text {
|
|
||||||
string += digitText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
guard let fields = self.digitFields else { return }
|
guard let newValue = newValue else { return }
|
||||||
|
|
||||||
for (index, field) in fields.enumerated() {
|
for (index, field) in digitFields.enumerated() {
|
||||||
if index < (text?.count ?? 0) {
|
if index < newValue.count {
|
||||||
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: index, length: 1))
|
let indexChar = newValue.index(newValue.startIndex, offsetBy: index)
|
||||||
field.text = stringForIndex
|
field.text = String(newValue[indexChar])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,9 +111,9 @@ import UIKit
|
|||||||
get { return titleLabel.text }
|
get { return titleLabel.text }
|
||||||
set {
|
set {
|
||||||
if let formText = newValue, !formText.isEmpty {
|
if let formText = newValue, !formText.isEmpty {
|
||||||
messageToTextFieldPin?.constant = 10
|
titleContainerDistance?.constant = 10
|
||||||
} else {
|
} else {
|
||||||
messageToTextFieldPin?.constant = 0
|
titleContainerDistance?.constant = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
super.title = newValue
|
super.title = newValue
|
||||||
@ -131,21 +126,17 @@ import UIKit
|
|||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
for field in self.digitFields ?? [] {
|
if self.showError {
|
||||||
field.showError(false)
|
self.feedbackContainerDistance?.constant = 10
|
||||||
|
self.setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.digitFields.forEach { $0.showErrorState(true) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Constraints
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
private weak var messageToTextFieldPin: NSLayoutConstraint?
|
|
||||||
private weak var labelToTextFieldPin: NSLayoutConstraint?
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -185,6 +176,7 @@ import UIKit
|
|||||||
|
|
||||||
open func setup() {
|
open func setup() {
|
||||||
|
|
||||||
|
hideBorder = true
|
||||||
titleLabel.styleB2(true)
|
titleLabel.styleB2(true)
|
||||||
alignCenterHorizontal()
|
alignCenterHorizontal()
|
||||||
}
|
}
|
||||||
@ -206,16 +198,11 @@ import UIKit
|
|||||||
|
|
||||||
self.titleLabel.updateView(size)
|
self.titleLabel.updateView(size)
|
||||||
|
|
||||||
|
if !self.digitFields.isEmpty {
|
||||||
|
|
||||||
if let digitFields = self.digitFields, !digitFields.isEmpty {
|
StackableViewController.remove(self.digitFields)
|
||||||
|
|
||||||
// Remove all current UI.
|
self.digitFields.forEach { $0.updateView(size) }
|
||||||
StackableViewController.remove(digitFields)
|
|
||||||
|
|
||||||
// Update text boxes.
|
|
||||||
for digitField in digitFields {
|
|
||||||
digitField.updateView(size)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout text boxes.
|
// Layout text boxes.
|
||||||
@ -227,6 +214,14 @@ import UIKit
|
|||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
func removeError() {
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.digitFields.forEach { $0.showErrorState(false) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createDigitField() -> DigitBox {
|
func createDigitField() -> DigitBox {
|
||||||
|
|
||||||
let textField = DigitBox()
|
let textField = DigitBox()
|
||||||
@ -239,22 +234,20 @@ import UIKit
|
|||||||
func buildTextFieldsView(size: CGFloat) {
|
func buildTextFieldsView(size: CGFloat) {
|
||||||
|
|
||||||
// Remove all current UI.
|
// Remove all current UI.
|
||||||
if let digitFields = digitFields, !digitFields.isEmpty {
|
if !digitFields.isEmpty {
|
||||||
StackableViewController.remove(digitFields)
|
StackableViewController.remove(digitFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
if numberOfDigits > 0 {
|
if numberOfDigits > 0 {
|
||||||
let digitFields = [DigitBox](repeating: createDigitField(), count: numberOfDigits)
|
let digitFields = [DigitBox](repeating: createDigitField(), count: numberOfDigits)
|
||||||
|
|
||||||
for digitField in digitFields {
|
digitFields.forEach { $0.updateView(size) }
|
||||||
digitField.updateView(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.digitFields = digitFields
|
self.digitFields = digitFields
|
||||||
setupTextFieldsView(forSize: size)
|
setupTextFieldsView(forSize: size)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
digitFields = nil
|
digitFields = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,10 +258,10 @@ import UIKit
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
if let feedback = self.feedback, !feedback.isEmpty {
|
if let feedback = self.feedback, !feedback.isEmpty {
|
||||||
self.labelToTextFieldPin?.constant = 10
|
self.feedbackContainerDistance?.constant = 10
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.labelToTextFieldPin?.constant = 0
|
self.feedbackContainerDistance?.constant = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,15 +269,13 @@ import UIKit
|
|||||||
func setAsSecureTextEntry(_ secureEntry: Bool) {
|
func setAsSecureTextEntry(_ secureEntry: Bool) {
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self,
|
guard let self = self else { return }
|
||||||
let fields = self.digitFields
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
for (index, field) in fields.enumerated() {
|
for (index, field) in self.digitFields.enumerated() {
|
||||||
field.isSecureTextEntry = secureEntry
|
field.isSecureTextEntry = secureEntry
|
||||||
|
|
||||||
// Accessibility - 33704 fix voice over will read what pin user is filling
|
// Accessibility - 33704 fix voice over will read what pin user is filling
|
||||||
field.accessibilityLabel = String(format: "PIN %lu of %lu", UInt(index) + 1, UInt(fields.count))
|
field.accessibilityLabel = String(format: "PIN %lu of %lu", UInt(index) + 1, UInt(self.digitFields.count))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,24 +283,21 @@ import UIKit
|
|||||||
func setupTextFieldsView(forSize size: CGFloat) {
|
func setupTextFieldsView(forSize size: CGFloat) {
|
||||||
|
|
||||||
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
|
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
|
||||||
let digitFieldsView = digitFieldsView,
|
let digitFieldsView = digitFieldsView
|
||||||
let digitFields = digitFields
|
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
StackableViewController.populateViewHorizontally(digitFieldsView, withUIArray: digitFields, withSpacingBlock: { object in
|
StackableViewController.populateViewHorizontally(digitFieldsView, withUIArray: digitFields, withSpacingBlock: { object in
|
||||||
|
|
||||||
var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space)
|
var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space)
|
||||||
|
|
||||||
guard let digitFields = self.digitFields else { return inset }
|
if self.digitFields.count == 1 {
|
||||||
|
|
||||||
if digitFields.count == 1 {
|
|
||||||
inset.left = 0
|
inset.left = 0
|
||||||
inset.right = 0
|
inset.right = 0
|
||||||
|
|
||||||
} else if let field = object as? UITextField, field == digitFields.first {
|
} else if let field = object as? UITextField, field == self.digitFields.first {
|
||||||
inset.left = 0
|
inset.left = 0
|
||||||
|
|
||||||
} else if let field = object as? UITextField, field == digitFields.last {
|
} else if let field = object as? UITextField, field == self.digitFields.last {
|
||||||
inset.right = 0
|
inset.right = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,57 +307,18 @@ import UIKit
|
|||||||
|
|
||||||
public override func defaultValidationBlock() {
|
public override func defaultValidationBlock() {
|
||||||
|
|
||||||
weak var weakSelf = self
|
|
||||||
|
|
||||||
validationBlock = { enteredValue in
|
validationBlock = { enteredValue in
|
||||||
|
guard let enteredValue = enteredValue else { return false }
|
||||||
|
|
||||||
if (enteredValue?.count ?? 0) > 0 && (enteredValue?.count ?? 0) == weakSelf?.digitFields?.count {
|
return enteredValue.count > 0 && enteredValue.count == self.digitFields.count
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Molecule
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
|
||||||
|
|
||||||
guard let dictionary = json else { return }
|
|
||||||
|
|
||||||
let digits = dictionary["digits"] as? Int ?? 4
|
|
||||||
if digits != numberOfDigits {
|
|
||||||
numberOfDigits = digits
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dictionary.isEmpty{
|
|
||||||
for textField in digitFields ?? [] {
|
|
||||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegateObject as? UITextFieldDelegate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
|
||||||
|
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
|
||||||
return 44
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Helpers
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
func selectPreviousTextField(_ currentTextField: UITextField?, clear: Bool) {
|
func selectPreviousTextField(_ currentTextField: UITextField?, clear: Bool) {
|
||||||
|
|
||||||
var selectNextField = false
|
var selectNextField = false
|
||||||
|
|
||||||
guard let fields = digitFields else { return }
|
for field in digitFields {
|
||||||
|
|
||||||
for field in fields {
|
|
||||||
|
|
||||||
if field == currentTextField {
|
if field == currentTextField {
|
||||||
selectNextField = true
|
selectNextField = true
|
||||||
@ -390,18 +339,16 @@ import UIKit
|
|||||||
|
|
||||||
var selectNextField = false
|
var selectNextField = false
|
||||||
|
|
||||||
guard let fields = digitFields else { return }
|
for field in digitFields {
|
||||||
|
|
||||||
for field in fields{
|
|
||||||
if field == currentTextField {
|
if field == currentTextField {
|
||||||
selectNextField = true
|
selectNextField = true
|
||||||
|
|
||||||
} else if selectNextField {
|
} else if selectNextField {
|
||||||
if !clear {
|
if !clear {
|
||||||
self.switchedAutomatically = true
|
switchedAutomatically = true
|
||||||
}
|
}
|
||||||
field.becomeFirstResponder()
|
field.becomeFirstResponder()
|
||||||
self.switchedAutomatically = false
|
switchedAutomatically = false
|
||||||
|
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: field)
|
UIAccessibility.post(notification: .layoutChanged, argument: field)
|
||||||
}
|
}
|
||||||
@ -409,20 +356,46 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Accessinility
|
// MARK: - Molecule
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override class func accessibilityElements() -> [Any]? {
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
// self.digit
|
|
||||||
// if let digitFields = self.digitFields {
|
guard let dictionary = json else { return }
|
||||||
// return [digitFields] + [textField]
|
|
||||||
// }
|
let digits = dictionary["digits"] as? Int ?? 4
|
||||||
//
|
if digits != numberOfDigits {
|
||||||
return [textField]
|
numberOfDigits = digits
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dictionary.isEmpty{
|
||||||
|
for textField in digitFields {
|
||||||
|
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegateObject as? UITextFieldDelegate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
||||||
|
|
||||||
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
return 44
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - TextFieldDelegate
|
// MARK: - Accessibility
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override class func accessibilityElements() -> [Any]? {
|
||||||
|
// let fields = []
|
||||||
|
|
||||||
|
// return self.digitFields
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Text Field Delegate
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
@ -495,7 +468,10 @@ import UIKit
|
|||||||
return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true
|
return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - Passed Along TextField delegate
|
// MARK: - Passed Along TextField delegate
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||||
|
|||||||
@ -14,23 +14,19 @@ import UIKit
|
|||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
let dropDownCaretLabel: Label = {
|
let dropDownCaretLabel: CaretView = {
|
||||||
let label = Label()
|
let caret = CaretView()
|
||||||
label.setContentHuggingPriority(UILayoutPriority(900), for: .horizontal)
|
caret.isHidden = true
|
||||||
label.setContentHuggingPriority(UILayoutPriority(251), for: .vertical)
|
caret.isUserInteractionEnabled = true
|
||||||
label.setContentCompressionResistancePriority(UILayoutPriority(900), for: .horizontal)
|
return caret
|
||||||
label.isHidden = true
|
|
||||||
label.isUserInteractionEnabled = true
|
|
||||||
return label
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private var calendar: Calendar?
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Accessories
|
// MARK: - Accessories
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public weak var datePicker: UIDatePicker?
|
public weak var datePicker: UIDatePicker?
|
||||||
|
private var calendar: Calendar?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
@ -39,9 +35,7 @@ import UIKit
|
|||||||
public var dropDownIsDisplayed = false
|
public var dropDownIsDisplayed = false
|
||||||
|
|
||||||
public override var isEnabled: Bool {
|
public override var isEnabled: Bool {
|
||||||
didSet {
|
didSet { showDropDown(isEnabled) }
|
||||||
showDropDown(isEnabled)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -56,10 +50,9 @@ import UIKit
|
|||||||
|
|
||||||
public override init(frame: CGRect) {
|
public override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
setupView()
|
setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Basic initializer.
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(frame: .zero)
|
self.init(frame: .zero)
|
||||||
}
|
}
|
||||||
@ -68,7 +61,7 @@ import UIKit
|
|||||||
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
|
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
setupView()
|
setup()
|
||||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: bothDelegates)
|
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: bothDelegates)
|
||||||
setBothTextDelegates(to: bothDelegates)
|
setBothTextDelegates(to: bothDelegates)
|
||||||
}
|
}
|
||||||
@ -78,6 +71,13 @@ import UIKit
|
|||||||
fatalError("DropdownEntryField does not support xib.")
|
fatalError("DropdownEntryField does not support xib.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func setup() {
|
||||||
|
|
||||||
|
dropDownCaretLabel.heightAnchor.constraint(equalToConstant: 40).isActive = true
|
||||||
|
dropDownCaretWidth = widthAnchor.constraint(equalToConstant: 40)
|
||||||
|
dropDownCaretWidth?.isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -116,7 +116,7 @@ import UIKit
|
|||||||
override func startEditing() {
|
override func startEditing() {
|
||||||
super.startEditing()
|
super.startEditing()
|
||||||
|
|
||||||
showDropDown(!showErrorMessage)
|
showDropDown(!showError)
|
||||||
}
|
}
|
||||||
|
|
||||||
class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? {
|
class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? {
|
||||||
|
|||||||
@ -43,6 +43,22 @@ import UIKit
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Delegate
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
weak var delegateObject: MVMCoreUIDelegateObject?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var isValid = false
|
||||||
|
public var fieldKey: String?
|
||||||
|
|
||||||
|
/// Determines if a border should be drawn.
|
||||||
|
var hideBorder = false
|
||||||
|
|
||||||
private var borderStrokeColor: UIColor = .mfSilver()
|
private var borderStrokeColor: UIColor = .mfSilver()
|
||||||
private var borderPath: UIBezierPath = UIBezierPath()
|
private var borderPath: UIBezierPath = UIBezierPath()
|
||||||
|
|
||||||
@ -55,21 +71,9 @@ import UIKit
|
|||||||
return layer
|
return layer
|
||||||
}()
|
}()
|
||||||
|
|
||||||
weak var delegateObject: MVMCoreUIDelegateObject?
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
public var isValid = false
|
|
||||||
public var fieldKey: String?
|
|
||||||
|
|
||||||
/// Determines if a border should be drawn.
|
|
||||||
private var hideBorder = false
|
|
||||||
|
|
||||||
public private(set) var appearance: Appearance = .original
|
public private(set) var appearance: Appearance = .original
|
||||||
|
|
||||||
public var showErrorMessage = false
|
public var showError = false
|
||||||
|
|
||||||
public var errorMessage: String?
|
public var errorMessage: String?
|
||||||
|
|
||||||
@ -133,6 +137,9 @@ import UIKit
|
|||||||
public var titleLabelLeading: NSLayoutConstraint?
|
public var titleLabelLeading: NSLayoutConstraint?
|
||||||
public var titleLabelTrailing: NSLayoutConstraint?
|
public var titleLabelTrailing: NSLayoutConstraint?
|
||||||
|
|
||||||
|
public var titleContainerDistance: NSLayoutConstraint?
|
||||||
|
public var feedbackContainerDistance: NSLayoutConstraint?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -150,7 +157,7 @@ import UIKit
|
|||||||
public init(title: String) {
|
public init(title: String) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
setupView()
|
setupView()
|
||||||
self.titleLabel.text = title
|
titleLabel.text = title
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init?(coder: NSCoder) {
|
required public init?(coder: NSCoder) {
|
||||||
@ -182,7 +189,8 @@ import UIKit
|
|||||||
addSubview(fieldContainer)
|
addSubview(fieldContainer)
|
||||||
setupFieldContainerContent(fieldContainer)
|
setupFieldContainerContent(fieldContainer)
|
||||||
|
|
||||||
fieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4).isActive = true
|
titleContainerDistance = fieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4)
|
||||||
|
titleContainerDistance?.isActive = true
|
||||||
fieldContainerLeading = fieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
fieldContainerLeading = fieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||||
fieldContainerLeading?.isActive = true
|
fieldContainerLeading?.isActive = true
|
||||||
fieldContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor)
|
fieldContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor)
|
||||||
@ -190,7 +198,8 @@ import UIKit
|
|||||||
|
|
||||||
addSubview(feedbackLabel)
|
addSubview(feedbackLabel)
|
||||||
|
|
||||||
feedbackLabel.topAnchor.constraint(equalTo: fieldContainer.bottomAnchor, constant: PaddingOne).isActive = true
|
feedbackContainerDistance = feedbackLabel.topAnchor.constraint(equalTo: fieldContainer.bottomAnchor, constant: PaddingOne)
|
||||||
|
feedbackContainerDistance?.isActive = true
|
||||||
feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||||
feedbackLabelLeading?.isActive = true
|
feedbackLabelLeading?.isActive = true
|
||||||
feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor)
|
feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor)
|
||||||
@ -203,10 +212,8 @@ import UIKit
|
|||||||
layoutIfNeeded()
|
layoutIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// Method to override.
|
||||||
Method to override.
|
/// Intended to add the interactive content (i.e. textField) to the fieldContainer.
|
||||||
Intended to add the interactive content (i.e. textField) to the fieldContainer.
|
|
||||||
*/
|
|
||||||
open func setupFieldContainerContent(_ container: UIView) {
|
open func setupFieldContainerContent(_ container: UIView) {
|
||||||
// To be overridden by subclass.
|
// To be overridden by subclass.
|
||||||
}
|
}
|
||||||
@ -237,7 +244,7 @@ import UIKit
|
|||||||
|
|
||||||
open func refreshBorderUI(bottomBarSize: CGFloat? = nil) {
|
open func refreshBorderUI(bottomBarSize: CGFloat? = nil) {
|
||||||
|
|
||||||
let size = CGFloat(appearance == .error ? 4 : 1)
|
let size: CGFloat = appearance == .error ? 4 : 1
|
||||||
bottomBar.frame = CGRect(x: 0, y: fieldContainer.bounds.height - size, width: fieldContainer.bounds.width, height: size)
|
bottomBar.frame = CGRect(x: 0, y: fieldContainer.bounds.height - size, width: fieldContainer.bounds.width, height: size)
|
||||||
|
|
||||||
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self)
|
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self)
|
||||||
@ -274,11 +281,6 @@ import UIKit
|
|||||||
layoutIfNeeded()
|
layoutIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
func resizeBottomBar(size: CGFloat) {
|
|
||||||
|
|
||||||
bottomBar.frame = CGRect(x: 0, y: fieldContainer.bounds.height - size, width: fieldContainer.bounds.width, height: size)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Constraint Methods
|
// MARK: - Constraint Methods
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -313,37 +315,30 @@ import UIKit
|
|||||||
|
|
||||||
self.appearance = appearance
|
self.appearance = appearance
|
||||||
isUserInteractionEnabled = true
|
isUserInteractionEnabled = true
|
||||||
|
titleLabel.textColor = .mfBattleshipGrey()
|
||||||
hideBorder = false
|
hideBorder = false
|
||||||
|
feedback = showError ? errorMessage : nil
|
||||||
|
|
||||||
switch appearance {
|
switch appearance {
|
||||||
case .original:
|
case .original:
|
||||||
borderStrokeColor = .mfSilver()
|
borderStrokeColor = .mfSilver()
|
||||||
feedback = nil
|
|
||||||
bottomBar.backgroundColor = UIColor.black.cgColor
|
bottomBar.backgroundColor = UIColor.black.cgColor
|
||||||
titleLabel.textColor = .mfBattleshipGrey()
|
|
||||||
|
|
||||||
case .error:
|
case .error:
|
||||||
borderStrokeColor = .mfPumpkin()
|
borderStrokeColor = .mfPumpkin()
|
||||||
titleLabel.textColor = UIColor.mfBattleshipGrey()
|
|
||||||
bottomBar.backgroundColor = UIColor.mfPumpkin().cgColor
|
bottomBar.backgroundColor = UIColor.mfPumpkin().cgColor
|
||||||
feedback = showErrorMessage ? errorMessage : nil
|
|
||||||
|
|
||||||
case .lock:
|
case .lock:
|
||||||
isUserInteractionEnabled = false
|
isUserInteractionEnabled = false
|
||||||
hideBorder = true
|
hideBorder = true
|
||||||
feedback = nil
|
|
||||||
titleLabel.textColor = UIColor.mfBattleshipGrey()
|
|
||||||
bottomBar.backgroundColor = UIColor.clear.cgColor
|
bottomBar.backgroundColor = UIColor.clear.cgColor
|
||||||
|
|
||||||
case .select:
|
case .select:
|
||||||
borderStrokeColor = .black
|
borderStrokeColor = .black
|
||||||
feedback = nil
|
|
||||||
titleLabel.textColor = UIColor.mfBattleshipGrey()
|
|
||||||
bottomBar.backgroundColor = UIColor.black.cgColor
|
bottomBar.backgroundColor = UIColor.black.cgColor
|
||||||
|
|
||||||
case .disable:
|
case .disable:
|
||||||
isUserInteractionEnabled = false
|
isUserInteractionEnabled = false
|
||||||
feedback = nil
|
|
||||||
borderStrokeColor = .mfSilver()
|
borderStrokeColor = .mfSilver()
|
||||||
titleLabel.textColor = self.isEnabled ? UIColor.mfBattleshipGrey() : UIColor.mfSilver()
|
titleLabel.textColor = self.isEnabled ? UIColor.mfBattleshipGrey() : UIColor.mfSilver()
|
||||||
bottomBar.backgroundColor = self.isEnabled ? UIColor.black.cgColor : UIColor.mfSilver().cgColor
|
bottomBar.backgroundColor = self.isEnabled ? UIColor.black.cgColor : UIColor.mfSilver().cgColor
|
||||||
|
|||||||
@ -20,8 +20,6 @@ import MVMCore
|
|||||||
public var isNationalMdn = true
|
public var isNationalMdn = true
|
||||||
public var shouldValidateMDN = false
|
public var shouldValidateMDN = false
|
||||||
|
|
||||||
// public var pickerView: UIPickerView?
|
|
||||||
|
|
||||||
public var mdn: String? {
|
public var mdn: String? {
|
||||||
get { return MVMCoreUIUtility.removeMdnFormat(text) }
|
get { return MVMCoreUIUtility.removeMdnFormat(text) }
|
||||||
set { text = MVMCoreUIUtility.formatMdn(newValue) }
|
set { text = MVMCoreUIUtility.formatMdn(newValue) }
|
||||||
@ -40,6 +38,13 @@ import MVMCore
|
|||||||
self.init(frame: .zero)
|
self.init(frame: .zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
|
||||||
|
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
setup()
|
||||||
|
setBothTextDelegates(to: bothDelegates)
|
||||||
|
}
|
||||||
|
|
||||||
required public init?(coder: NSCoder) {
|
required public init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
fatalError("MdnEntryField xib not supported.")
|
fatalError("MdnEntryField xib not supported.")
|
||||||
@ -65,7 +70,7 @@ import MVMCore
|
|||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
func hasValidMDN() -> Bool {
|
public func hasValidMDN() -> Bool {
|
||||||
|
|
||||||
guard let MDN = mdn,
|
guard let MDN = mdn,
|
||||||
!MDN.isEmpty
|
!MDN.isEmpty
|
||||||
@ -78,7 +83,7 @@ import MVMCore
|
|||||||
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
|
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateAndColor() -> Bool {
|
public func validateAndColor() -> Bool {
|
||||||
|
|
||||||
if !shouldValidateMDN {
|
if !shouldValidateMDN {
|
||||||
let isValid = hasValidMDN()
|
let isValid = hasValidMDN()
|
||||||
@ -107,7 +112,7 @@ import MVMCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - ContactPicker Delegate
|
// MARK: - Contact Picker Delegate
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
|
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
|
||||||
@ -127,7 +132,7 @@ import MVMCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
text = unformattedMDN
|
text = unformattedMDN
|
||||||
textFieldShouldReturn(textField)
|
_ = textFieldShouldReturn(textField)
|
||||||
textFieldDidEndEditing(textField)
|
textFieldDidEndEditing(textField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,15 +141,14 @@ import MVMCore
|
|||||||
// MARK: - Implemented TextField Delegate
|
// MARK: - Implemented TextField Delegate
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
@discardableResult
|
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
|
||||||
|
|
||||||
textField.resignFirstResponder()
|
textField.resignFirstResponder()
|
||||||
|
|
||||||
return uiTextFieldDelegate?.textFieldShouldReturn?(textField) ?? true
|
return uiTextFieldDelegate?.textFieldShouldReturn?(textField) ?? true
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
|
|
||||||
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
|
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
|
||||||
return false
|
return false
|
||||||
@ -172,17 +176,17 @@ import MVMCore
|
|||||||
// MARK: - Passed Along TextField delegate
|
// MARK: - Passed Along TextField delegate
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
return uiTextFieldDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
return uiTextFieldDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true
|
return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,15 +65,11 @@ import UIKit
|
|||||||
|
|
||||||
public var placeholder: String? {
|
public var placeholder: String? {
|
||||||
get { return textField.placeholder }
|
get { return textField.placeholder }
|
||||||
set {
|
set { textField.placeholder = newValue }
|
||||||
textField.placeholder = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var validationBlock: ((_ value: String?) -> Bool)? {
|
public var validationBlock: ((_ value: String?) -> Bool)? {
|
||||||
didSet {
|
didSet { valueChanged() }
|
||||||
valueChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override var errorMessage: String? {
|
public override var errorMessage: String? {
|
||||||
@ -174,6 +170,21 @@ import UIKit
|
|||||||
|
|
||||||
open func clearErrorState() {
|
open func clearErrorState() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||||
|
self.separatorHeightConstraint.constant = 1;
|
||||||
|
self.separatorView.backgroundColor = [UIColor blackColor];
|
||||||
|
[self layoutIfNeeded];
|
||||||
|
self.errorShowing = NO;
|
||||||
|
self.label.textColor = [UIColor blackColor];
|
||||||
|
self.label.text = @"";
|
||||||
|
self.textField.accessibilityValue = nil;
|
||||||
|
[self setNeedsDisplay];
|
||||||
|
[self layoutIfNeeded];
|
||||||
|
}];
|
||||||
|
*/
|
||||||
|
|
||||||
textField.accessibilityValue = nil
|
textField.accessibilityValue = nil
|
||||||
updateUI(appearance: .original)
|
updateUI(appearance: .original)
|
||||||
}
|
}
|
||||||
@ -202,7 +213,7 @@ import UIKit
|
|||||||
|
|
||||||
@objc func valueChanged() {
|
@objc func valueChanged() {
|
||||||
|
|
||||||
if !showErrorMessage {
|
if !showError {
|
||||||
feedback = ""
|
feedback = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,10 +228,7 @@ import UIKit
|
|||||||
|
|
||||||
} else if !previousValidity && isValid {
|
} else if !previousValidity && isValid {
|
||||||
clearErrorState()
|
clearErrorState()
|
||||||
|
mfTextFieldDelegate?.isValid?(textfield: self)
|
||||||
if let mfTextFieldDelegate = mfTextFieldDelegate {
|
|
||||||
mfTextFieldDelegate.isValid?(textfield: self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +236,7 @@ import UIKit
|
|||||||
|
|
||||||
if isValid {
|
if isValid {
|
||||||
clearErrorState()
|
clearErrorState()
|
||||||
|
bottomBar.backgroundColor = UIColor.black.cgColor
|
||||||
|
|
||||||
} else if let errMessage = errorMessage {
|
} else if let errMessage = errorMessage {
|
||||||
feedback = errMessage
|
feedback = errMessage
|
||||||
@ -236,6 +245,10 @@ import UIKit
|
|||||||
|
|
||||||
@objc func startEditing() {
|
@objc func startEditing() {
|
||||||
|
|
||||||
|
if appearance != .original {
|
||||||
|
updateUI(appearance: .original)
|
||||||
|
}
|
||||||
|
|
||||||
textField.becomeFirstResponder()
|
textField.becomeFirstResponder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,52 +2,53 @@
|
|||||||
// CaretView.swift
|
// CaretView.swift
|
||||||
// MobileFirstFramework
|
// MobileFirstFramework
|
||||||
//
|
//
|
||||||
// Created by Kolli, Praneeth on 1/5/18.
|
// Created by Christiano, Kevin on 1/5/18.
|
||||||
// Converted by Christiano, Kevin on 1/5/18.
|
|
||||||
// Copyright © 2018 Verizon Wireless. All rights reserved.
|
// Copyright © 2018 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
open class CaretView: MFView {
|
@objcMembers open class CaretView: MFView {
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
// Objc can't use float enum.
|
// Objc can't use float enum.
|
||||||
@objc public static let thin: CGFloat = 6.0
|
public static let thin: CGFloat = 6.0
|
||||||
@objc public static let standard: CGFloat = 2.6
|
public static let standard: CGFloat = 2.5
|
||||||
@objc public static let thick: CGFloat = 1.5
|
public static let thick: CGFloat = 1.5
|
||||||
|
|
||||||
private(set) var strokeColor: UIColor?
|
public var strokeColor: UIColor = .black
|
||||||
private var lineWidth: CGFloat?
|
public var lineWidth: CGFloat = 1
|
||||||
private var lineThickness: CGFloat?
|
public var direction: Direction = .right
|
||||||
|
|
||||||
|
private var caretPath: UIBezierPath = UIBezierPath()
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
@objc public init() {
|
|
||||||
super.init(frame: .zero)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public override init(frame: CGRect) {
|
@objc public override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc required public init?(coder aDecoder: NSCoder) {
|
@objc public init() {
|
||||||
super.init(coder: aDecoder)
|
super.init(frame: .zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can init with a specific line width.
|
|
||||||
@objc public init(lineWidth: CGFloat) {
|
@objc public init(lineWidth: CGFloat) {
|
||||||
super.init(frame: CGRect())
|
super.init(frame: .zero)
|
||||||
self.lineWidth = lineWidth
|
self.lineWidth = lineWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can init with a specific line thickness, scales based on width and height.
|
/// Can init with a specific line thickness, scales based on width and height.
|
||||||
@objc public init(lineThickness: CGFloat) {
|
@objc public init(lineThickness: CGFloat) {
|
||||||
super.init(frame: CGRect())
|
super.init(frame: .zero)
|
||||||
self.lineThickness = lineThickness
|
// self.lineThickness = lineThickness
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc required public init?(coder aDecoder: NSCoder) {
|
||||||
|
super.init(coder: aDecoder)
|
||||||
|
fatalError("CaretView xib not supported.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc override open func setupView() {
|
@objc override open func setupView() {
|
||||||
@ -55,9 +56,60 @@ open class CaretView: MFView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Private Function
|
// MARK: - Drawing
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
/// The direction the caret will be pointing to.
|
||||||
|
public enum Direction: String {
|
||||||
|
case left
|
||||||
|
case right
|
||||||
|
case down
|
||||||
|
case up
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc override open func draw(_ rect: CGRect) {
|
||||||
|
super.draw(rect)
|
||||||
|
|
||||||
|
caretPath.removeAllPoints()
|
||||||
|
caretPath.lineJoinStyle = .miter
|
||||||
|
caretPath.lineWidth = lineWidth
|
||||||
|
let inset = lineWidth / 2
|
||||||
|
|
||||||
|
switch direction {
|
||||||
|
case .up:
|
||||||
|
caretPath.move(to: CGPoint(x: inset, y: frame.size.height - inset))
|
||||||
|
caretPath.addLine(to: CGPoint(x: frame.size.width / 2, y: inset))
|
||||||
|
caretPath.addLine(to: CGPoint(x: frame.size.width, y: frame.size.height))
|
||||||
|
|
||||||
|
case .right:
|
||||||
|
caretPath.move(to: CGPoint(x: inset, y: inset))
|
||||||
|
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: frame.size.height / 2))
|
||||||
|
caretPath.addLine(to: CGPoint(x: inset, y: frame.size.height - inset))
|
||||||
|
|
||||||
|
case .down:
|
||||||
|
caretPath.move(to: CGPoint(x: inset, y: inset))
|
||||||
|
caretPath.addLine(to: CGPoint(x: frame.size.width / 2, y: frame.size.height - inset))
|
||||||
|
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: inset))
|
||||||
|
|
||||||
|
case .left:
|
||||||
|
caretPath.move(to: CGPoint(x: frame.size.width - inset, y: inset))
|
||||||
|
caretPath.addLine(to: CGPoint(x: inset, y: frame.size.height / 2))
|
||||||
|
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: frame.size.height - inset))
|
||||||
|
}
|
||||||
|
|
||||||
|
strokeColor.setStroke()
|
||||||
|
caretPath.stroke()
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
@objc public func setLineColor(_ color: UIColor) {
|
||||||
|
strokeColor = color
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
private func defaultState() {
|
private func defaultState() {
|
||||||
isOpaque = false
|
isOpaque = false
|
||||||
isHidden = false
|
isHidden = false
|
||||||
@ -65,34 +117,6 @@ open class CaretView: MFView {
|
|||||||
strokeColor = .black
|
strokeColor = .black
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
|
||||||
// MARK: - Drawing
|
|
||||||
//------------------------------------------------------
|
|
||||||
|
|
||||||
@objc override open func draw(_ rect: CGRect) {
|
|
||||||
// Drawing Caret
|
|
||||||
let context = UIGraphicsGetCurrentContext()
|
|
||||||
context?.clear(rect)
|
|
||||||
|
|
||||||
let lineWidthToDraw: CGFloat = lineWidth ?? frame.size.width / (lineThickness ?? 2.6)
|
|
||||||
|
|
||||||
let path = UIBezierPath()
|
|
||||||
path.move(to: CGPoint(x: lineWidthToDraw / 2.0, y: 0.0))
|
|
||||||
path.addLine(to: CGPoint(x: frame.size.width, y: frame.size.height / 2.0))
|
|
||||||
path.addLine(to: CGPoint(x: lineWidthToDraw / 2.0, y: frame.size.height))
|
|
||||||
path.addLine(to: CGPoint(x: 0.0, y: frame.size.height - lineWidthToDraw / 2.0))
|
|
||||||
path.addLine(to: CGPoint(x: frame.size.width - lineWidthToDraw, y: frame.size.height / 2.0))
|
|
||||||
path.addLine(to: CGPoint(x: 0.0, y: lineWidthToDraw / 2.0))
|
|
||||||
path.addLine(to: CGPoint(x: lineWidthToDraw / 2.0, y: 0.0))
|
|
||||||
strokeColor?.setFill()
|
|
||||||
path.fill()
|
|
||||||
path.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func setLineColor(_ color: UIColor?) {
|
|
||||||
strokeColor = color
|
|
||||||
setNeedsDisplay()
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Atomization
|
// MARK: - Atomization
|
||||||
@ -105,7 +129,7 @@ open class CaretView: MFView {
|
|||||||
|
|
||||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
// Configure class properties with JSON values
|
|
||||||
guard let dictionary = json else { return }
|
guard let dictionary = json else { return }
|
||||||
|
|
||||||
if let strokeColorHex = dictionary["strokeColor"] as? String {
|
if let strokeColorHex = dictionary["strokeColor"] as? String {
|
||||||
@ -130,6 +154,6 @@ open class CaretView: MFView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override func alignment() -> UIStackView.Alignment {
|
open override func alignment() -> UIStackView.Alignment {
|
||||||
return UIStackView.Alignment.leading;
|
return .leading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ open class DashLine: MFView {
|
|||||||
|
|
||||||
required public init?(coder: NSCoder) {
|
required public init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
fatalError("DashLine xib not supported")
|
// fatalError("DashLine xib not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user