From 475d08296b3ec1d5e55a89273cd28d450ef80d48 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 1 Nov 2019 16:15:19 -0400 Subject: [PATCH] Reworked bezier logic for CaretView. It was not optimal. --- MVMCoreUI/Atoms/TextFields/DigitBox.swift | 25 +- .../Atoms/TextFields/DigitEntryField.swift | 266 ++++++++---------- .../Atoms/TextFields/DropdownEntryField.swift | 34 +-- .../Atoms/TextFields/FormEntryField.swift | 65 ++--- .../Atoms/TextFields/MdnEntryField.swift | 28 +- .../Atoms/TextFields/TextEntryField.swift | 35 ++- MVMCoreUI/Atoms/Views/CaretView.swift | 130 +++++---- MVMCoreUI/Atoms/Views/DashLine.swift | 2 +- 8 files changed, 300 insertions(+), 285 deletions(-) diff --git a/MVMCoreUI/Atoms/TextFields/DigitBox.swift b/MVMCoreUI/Atoms/TextFields/DigitBox.swift index a9bb85d0..f4edd1a1 100644 --- a/MVMCoreUI/Atoms/TextFields/DigitBox.swift +++ b/MVMCoreUI/Atoms/TextFields/DigitBox.swift @@ -25,8 +25,6 @@ import UIKit return layer }() - weak var textBoxDelegate: DigitBoxDelegate? - private var previousSize: CGFloat = 0.0 /// Determines if a border should be drawn. @@ -36,6 +34,12 @@ import UIKit private var borderStrokeColor: UIColor = .mfSilver() private var borderPath: UIBezierPath = UIBezierPath() + //-------------------------------------------------- + // MARK: - Delegate + //-------------------------------------------------- + + weak var textBoxDelegate: DigitBoxDelegate? + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -47,11 +51,6 @@ import UIKit // MARK: - Initializers //-------------------------------------------------- - required public init?(coder: NSCoder) { - super.init(coder: coder) - fatalError("DigitBox has not been implemented") - } - public override init(frame: CGRect) { super.init(frame: frame) setup() @@ -61,11 +60,16 @@ import UIKit self.init(frame: .zero) } + required public init?(coder: NSCoder) { + super.init(coder: coder) + fatalError("DigitBox has not been implemented") + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - func setup() { + private func setup() { guard constraints.isEmpty else { return } @@ -74,7 +78,7 @@ import UIKit textAlignment = .center keyboardType = .numberPad layer.borderWidth = 1 - showError(false) + showErrorState(false) widthConstraint = widthAnchor.constraint(equalToConstant: 39) widthConstraint?.isActive = true @@ -83,7 +87,6 @@ import UIKit heightConstraint?.isActive = true layer.addSublayer(bottomBar) - updateView(MVMCoreUISplitViewController.getDetailViewWidth()) } @@ -161,7 +164,7 @@ import UIKit } } - func showError(_ show: Bool) { + func showErrorState(_ show: Bool) { showError = show borderStrokeColor = show ? .mfPumpkin() : .mfSilver() diff --git a/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift b/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift index 34c3afc5..86fbae9a 100644 --- a/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift @@ -8,7 +8,10 @@ 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 { //-------------------------------------------------- // MARK: - Outlets @@ -20,69 +23,65 @@ import UIKit // MARK: - Properties //-------------------------------------------------- - private var numberOfDigits = 0 + private var numberOfDigits = 4 private var switchedAutomatically = false - public var digitFields: [DigitBox]? + public var digitFields: [DigitBox] = [] public override var isEnabled: Bool { didSet { if isEnabled { titleLabel.styleB2(true) } else { - titleLabel.textColor = UIColor.mfBattleshipGrey() + titleLabel.textColor = .mfBattleshipGrey() } - for textField in digitFields ?? [] { + for textField in digitFields { textField.isUserInteractionEnabled = isEnabled textField.isEnabled = isEnabled - textField.textColor = isEnabled ? .black : UIColor.mfBattleshipGrey() + textField.textColor = isEnabled ? .black : .mfBattleshipGrey() } } } /// Sets placeholder text in the textField. - public override var feedback: String? { + public override var placeholder: String? { get { var string = "" - for digitField in digitFields ?? [] { - if let digitext = digitField.attributedPlaceholder?.string { - string += digitext - } - } - + digitFields.forEach { string += $0.attributedPlaceholder?.string ?? "" } + return !string.isEmpty ? string : nil } set { - guard let fieldValue = newValue, let fields = digitFields else { return } + guard let newValue = newValue else { return } - for (index, field) in fields.enumerated() { - if index < fieldValue.count { - let stringForIndex = (newValue as NSString?)?.substring(with: NSRange(location: index, length: 1)) - field.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [ + for (index, field) in digitFields.enumerated() { + if index < newValue.count { + let indexChar = newValue.index(newValue.startIndex, offsetBy: index) + field.attributedPlaceholder = NSAttributedString(string: String(newValue[indexChar]), attributes: [ NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()]) } } - // - // if feedback.text.length > 0 { - // labelToTextFieldPin?.constant = 10 - // } else { - // labelToTextFieldPin?.constant = 0 - // } - // 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")) - // - // super.showErrorMessage(errorMessage) - // - // if self.showErrorMessage { - // self.labelToTextFieldPin?.constant = 10 - // } - // for field in self.digitFields ?? [] { - // field.setAsError() - // } + // If there is already text in the textfield, set the place holder label below. + if let text = text, !text.isEmpty && !showError { + feedback = placeholder + } else if !showError { + feedback = "" + } + + if let feedback = feedback, !feedback.isEmpty { + feedbackContainerDistance?.constant = 10 + } else { + feedbackContainerDistance?.constant = 0 + } + + /* + * 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 { var string = "" - for digitField in digitFields ?? [] { - if let digitText = digitField.text { - string += digitText - } - } - + digitFields.forEach { string += $0.text ?? "" } + return string } set { - guard let fields = self.digitFields else { return } + guard let newValue = newValue else { return } - for (index, field) in fields.enumerated() { - if index < (text?.count ?? 0) { - let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: index, length: 1)) - field.text = stringForIndex + for (index, field) in digitFields.enumerated() { + if index < newValue.count { + let indexChar = newValue.index(newValue.startIndex, offsetBy: index) + field.text = String(newValue[indexChar]) } } @@ -116,9 +111,9 @@ import UIKit get { return titleLabel.text } set { if let formText = newValue, !formText.isEmpty { - messageToTextFieldPin?.constant = 10 + titleContainerDistance?.constant = 10 } else { - messageToTextFieldPin?.constant = 0 + titleContainerDistance?.constant = 0 } super.title = newValue @@ -131,21 +126,17 @@ import UIKit DispatchQueue.main.async { [weak self] in guard let self = self else { return } - for field in self.digitFields ?? [] { - field.showError(false) + if self.showError { + 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 //-------------------------------------------------- @@ -185,6 +176,7 @@ import UIKit open func setup() { + hideBorder = true titleLabel.styleB2(true) alignCenterHorizontal() } @@ -206,16 +198,11 @@ import UIKit self.titleLabel.updateView(size) - - if let digitFields = self.digitFields, !digitFields.isEmpty { - - // Remove all current UI. - StackableViewController.remove(digitFields) - - // Update text boxes. - for digitField in digitFields { - digitField.updateView(size) - } + if !self.digitFields.isEmpty { + + StackableViewController.remove(self.digitFields) + + self.digitFields.forEach { $0.updateView(size) } } // Layout text boxes. @@ -227,6 +214,14 @@ import UIKit // 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 { let textField = DigitBox() @@ -239,22 +234,20 @@ import UIKit func buildTextFieldsView(size: CGFloat) { // Remove all current UI. - if let digitFields = digitFields, !digitFields.isEmpty { + if !digitFields.isEmpty { StackableViewController.remove(digitFields) } if numberOfDigits > 0 { let digitFields = [DigitBox](repeating: createDigitField(), count: numberOfDigits) - for digitField in digitFields { - digitField.updateView(size) - } + digitFields.forEach { $0.updateView(size) } self.digitFields = digitFields setupTextFieldsView(forSize: size) } else { - digitFields = nil + digitFields = [] } } @@ -265,10 +258,10 @@ import UIKit guard let self = self else { return } if let feedback = self.feedback, !feedback.isEmpty { - self.labelToTextFieldPin?.constant = 10 + self.feedbackContainerDistance?.constant = 10 } else { - self.labelToTextFieldPin?.constant = 0 + self.feedbackContainerDistance?.constant = 0 } } } @@ -276,15 +269,13 @@ import UIKit func setAsSecureTextEntry(_ secureEntry: Bool) { DispatchQueue.main.async { [weak self] in - guard let self = self, - let fields = self.digitFields - else { return } + guard let self = self else { return } - for (index, field) in fields.enumerated() { + for (index, field) in self.digitFields.enumerated() { field.isSecureTextEntry = secureEntry // 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) { guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(), - let digitFieldsView = digitFieldsView, - let digitFields = digitFields + let digitFieldsView = digitFieldsView else { return } StackableViewController.populateViewHorizontally(digitFieldsView, withUIArray: digitFields, withSpacingBlock: { object in var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space) - guard let digitFields = self.digitFields else { return inset } - - if digitFields.count == 1 { + if self.digitFields.count == 1 { inset.left = 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 - } else if let field = object as? UITextField, field == digitFields.last { + } else if let field = object as? UITextField, field == self.digitFields.last { inset.right = 0 } @@ -319,57 +307,18 @@ import UIKit public override func defaultValidationBlock() { - weak var weakSelf = self - validationBlock = { enteredValue in - - if (enteredValue?.count ?? 0) > 0 && (enteredValue?.count ?? 0) == weakSelf?.digitFields?.count { - return true - } - - return false + guard let enteredValue = enteredValue else { return false } + + return enteredValue.count > 0 && enteredValue.count == self.digitFields.count } } - //-------------------------------------------------- - // 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) { var selectNextField = false - guard let fields = digitFields else { return } - - for field in fields { + for field in digitFields { if field == currentTextField { selectNextField = true @@ -390,18 +339,16 @@ import UIKit var selectNextField = false - guard let fields = digitFields else { return } - - for field in fields{ + for field in digitFields { if field == currentTextField { selectNextField = true } else if selectNextField { if !clear { - self.switchedAutomatically = true + switchedAutomatically = true } field.becomeFirstResponder() - self.switchedAutomatically = false + switchedAutomatically = false UIAccessibility.post(notification: .layoutChanged, argument: field) } @@ -409,20 +356,46 @@ import UIKit } //-------------------------------------------------- - // MARK: - Accessinility + // MARK: - Molecule //-------------------------------------------------- - open override class func accessibilityElements() -> [Any]? { - // self.digit - // if let digitFields = self.digitFields { - // return [digitFields] + [textField] - // } - // - return [textField] + 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: - 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 { @@ -495,7 +468,10 @@ import UIKit return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true } + //-------------------------------------------------- // MARK: - Passed Along TextField delegate + //-------------------------------------------------- + @objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true diff --git a/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift b/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift index 2f1bcbaa..17627b69 100644 --- a/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift @@ -14,23 +14,19 @@ import UIKit // MARK: - Outlets //-------------------------------------------------- - let dropDownCaretLabel: Label = { - let label = Label() - label.setContentHuggingPriority(UILayoutPriority(900), for: .horizontal) - label.setContentHuggingPriority(UILayoutPriority(251), for: .vertical) - label.setContentCompressionResistancePriority(UILayoutPriority(900), for: .horizontal) - label.isHidden = true - label.isUserInteractionEnabled = true - return label + let dropDownCaretLabel: CaretView = { + let caret = CaretView() + caret.isHidden = true + caret.isUserInteractionEnabled = true + return caret }() - private var calendar: Calendar? - //-------------------------------------------------- // MARK: - Accessories //-------------------------------------------------- public weak var datePicker: UIDatePicker? + private var calendar: Calendar? //-------------------------------------------------- // MARK: - Properties @@ -39,9 +35,7 @@ import UIKit public var dropDownIsDisplayed = false public override var isEnabled: Bool { - didSet { - showDropDown(isEnabled) - } + didSet { showDropDown(isEnabled) } } //-------------------------------------------------- @@ -56,10 +50,9 @@ import UIKit public override init(frame: CGRect) { super.init(frame: frame) - setupView() + setup() } - /// Basic initializer. public convenience init() { self.init(frame: .zero) } @@ -68,7 +61,7 @@ import UIKit public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) { super.init(frame: .zero) - setupView() + setup() MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: bothDelegates) setBothTextDelegates(to: bothDelegates) } @@ -78,6 +71,13 @@ import UIKit 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 //-------------------------------------------------- @@ -116,7 +116,7 @@ import UIKit override func startEditing() { super.startEditing() - showDropDown(!showErrorMessage) + showDropDown(!showError) } class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? { diff --git a/MVMCoreUI/Atoms/TextFields/FormEntryField.swift b/MVMCoreUI/Atoms/TextFields/FormEntryField.swift index ce1ffeba..40157483 100644 --- a/MVMCoreUI/Atoms/TextFields/FormEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/FormEntryField.swift @@ -43,6 +43,22 @@ import UIKit 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 borderPath: UIBezierPath = UIBezierPath() @@ -55,21 +71,9 @@ import UIKit 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 var showErrorMessage = false + public var showError = false public var errorMessage: String? @@ -133,6 +137,9 @@ import UIKit public var titleLabelLeading: NSLayoutConstraint? public var titleLabelTrailing: NSLayoutConstraint? + public var titleContainerDistance: NSLayoutConstraint? + public var feedbackContainerDistance: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -150,7 +157,7 @@ import UIKit public init(title: String) { super.init(frame: .zero) setupView() - self.titleLabel.text = title + titleLabel.text = title } required public init?(coder: NSCoder) { @@ -182,7 +189,8 @@ import UIKit addSubview(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?.isActive = true fieldContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor) @@ -190,7 +198,8 @@ import UIKit 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?.isActive = true feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor) @@ -203,10 +212,8 @@ import UIKit layoutIfNeeded() } - /** - Method to override. - Intended to add the interactive content (i.e. textField) to the fieldContainer. - */ + /// Method to override. + /// Intended to add the interactive content (i.e. textField) to the fieldContainer. open func setupFieldContainerContent(_ container: UIView) { // To be overridden by subclass. } @@ -237,7 +244,7 @@ import UIKit 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) self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self) @@ -274,11 +281,6 @@ import UIKit layoutIfNeeded() } - func resizeBottomBar(size: CGFloat) { - - bottomBar.frame = CGRect(x: 0, y: fieldContainer.bounds.height - size, width: fieldContainer.bounds.width, height: size) - } - //-------------------------------------------------- // MARK: - Constraint Methods //-------------------------------------------------- @@ -313,37 +315,30 @@ import UIKit self.appearance = appearance isUserInteractionEnabled = true + titleLabel.textColor = .mfBattleshipGrey() hideBorder = false + feedback = showError ? errorMessage : nil switch appearance { case .original: borderStrokeColor = .mfSilver() - feedback = nil bottomBar.backgroundColor = UIColor.black.cgColor - titleLabel.textColor = .mfBattleshipGrey() case .error: borderStrokeColor = .mfPumpkin() - titleLabel.textColor = UIColor.mfBattleshipGrey() bottomBar.backgroundColor = UIColor.mfPumpkin().cgColor - feedback = showErrorMessage ? errorMessage : nil case .lock: isUserInteractionEnabled = false hideBorder = true - feedback = nil - titleLabel.textColor = UIColor.mfBattleshipGrey() bottomBar.backgroundColor = UIColor.clear.cgColor case .select: borderStrokeColor = .black - feedback = nil - titleLabel.textColor = UIColor.mfBattleshipGrey() bottomBar.backgroundColor = UIColor.black.cgColor case .disable: isUserInteractionEnabled = false - feedback = nil borderStrokeColor = .mfSilver() titleLabel.textColor = self.isEnabled ? UIColor.mfBattleshipGrey() : UIColor.mfSilver() bottomBar.backgroundColor = self.isEnabled ? UIColor.black.cgColor : UIColor.mfSilver().cgColor diff --git a/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift b/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift index 06252a76..f1b769d5 100644 --- a/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift @@ -20,8 +20,6 @@ import MVMCore public var isNationalMdn = true public var shouldValidateMDN = false -// public var pickerView: UIPickerView? - public var mdn: String? { get { return MVMCoreUIUtility.removeMdnFormat(text) } set { text = MVMCoreUIUtility.formatMdn(newValue) } @@ -40,6 +38,13 @@ import MVMCore 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) { super.init(coder: coder) fatalError("MdnEntryField xib not supported.") @@ -65,7 +70,7 @@ import MVMCore // MARK: - Methods //-------------------------------------------------- - func hasValidMDN() -> Bool { + public func hasValidMDN() -> Bool { guard let MDN = mdn, !MDN.isEmpty @@ -78,7 +83,7 @@ import MVMCore return MVMCoreUIUtility.validateInternationalMDNString(MDN) } - func validateAndColor() -> Bool { + public func validateAndColor() -> Bool { if !shouldValidateMDN { let isValid = hasValidMDN() @@ -107,7 +112,7 @@ import MVMCore } //-------------------------------------------------- - // MARK: - ContactPicker Delegate + // MARK: - Contact Picker Delegate //-------------------------------------------------- public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) { @@ -127,7 +132,7 @@ import MVMCore } text = unformattedMDN - textFieldShouldReturn(textField) + _ = textFieldShouldReturn(textField) textFieldDidEndEditing(textField) } } @@ -136,15 +141,14 @@ import MVMCore // MARK: - Implemented TextField Delegate //-------------------------------------------------- - @discardableResult - @objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool { + public func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() 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) { return false @@ -172,17 +176,17 @@ import MVMCore // MARK: - Passed Along TextField delegate //-------------------------------------------------- - @objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { + public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true } - @objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { + public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { return uiTextFieldDelegate?.textFieldShouldEndEditing?(textField) ?? true } - @objc public func textFieldShouldClear(_ textField: UITextField) -> Bool { + public func textFieldShouldClear(_ textField: UITextField) -> Bool { return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true } diff --git a/MVMCoreUI/Atoms/TextFields/TextEntryField.swift b/MVMCoreUI/Atoms/TextFields/TextEntryField.swift index 46664042..53807ec5 100644 --- a/MVMCoreUI/Atoms/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/TextEntryField.swift @@ -65,15 +65,11 @@ import UIKit public var placeholder: String? { get { return textField.placeholder } - set { - textField.placeholder = newValue - } + set { textField.placeholder = newValue } } public var validationBlock: ((_ value: String?) -> Bool)? { - didSet { - valueChanged() - } + didSet { valueChanged() } } public override var errorMessage: String? { @@ -174,6 +170,21 @@ import UIKit 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 updateUI(appearance: .original) } @@ -202,7 +213,7 @@ import UIKit @objc func valueChanged() { - if !showErrorMessage { + if !showError { feedback = "" } @@ -217,10 +228,7 @@ import UIKit } else if !previousValidity && isValid { clearErrorState() - - if let mfTextFieldDelegate = mfTextFieldDelegate { - mfTextFieldDelegate.isValid?(textfield: self) - } + mfTextFieldDelegate?.isValid?(textfield: self) } } @@ -228,6 +236,7 @@ import UIKit if isValid { clearErrorState() + bottomBar.backgroundColor = UIColor.black.cgColor } else if let errMessage = errorMessage { feedback = errMessage @@ -236,6 +245,10 @@ import UIKit @objc func startEditing() { + if appearance != .original { + updateUI(appearance: .original) + } + textField.becomeFirstResponder() } } diff --git a/MVMCoreUI/Atoms/Views/CaretView.swift b/MVMCoreUI/Atoms/Views/CaretView.swift index ec4457c2..4f1f80eb 100644 --- a/MVMCoreUI/Atoms/Views/CaretView.swift +++ b/MVMCoreUI/Atoms/Views/CaretView.swift @@ -2,52 +2,53 @@ // CaretView.swift // MobileFirstFramework // -// Created by Kolli, Praneeth on 1/5/18. -// Converted by Christiano, Kevin on 1/5/18. +// Created by Christiano, Kevin on 1/5/18. // Copyright © 2018 Verizon Wireless. All rights reserved. // -open class CaretView: MFView { +@objcMembers open class CaretView: MFView { //------------------------------------------------------ // MARK: - Properties //------------------------------------------------------ // Objc can't use float enum. - @objc public static let thin: CGFloat = 6.0 - @objc public static let standard: CGFloat = 2.6 - @objc public static let thick: CGFloat = 1.5 + public static let thin: CGFloat = 6.0 + public static let standard: CGFloat = 2.5 + public static let thick: CGFloat = 1.5 + + public var strokeColor: UIColor = .black + public var lineWidth: CGFloat = 1 + public var direction: Direction = .right + + private var caretPath: UIBezierPath = UIBezierPath() - private(set) var strokeColor: UIColor? - private var lineWidth: CGFloat? - private var lineThickness: CGFloat? - //------------------------------------------------------ // MARK: - Initialization //------------------------------------------------------ - @objc public init() { - super.init(frame: .zero) - } - @objc public override init(frame: CGRect) { super.init(frame: frame) } - @objc required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) + @objc public init() { + super.init(frame: .zero) } - /// Can init with a specific line width. @objc public init(lineWidth: CGFloat) { - super.init(frame: CGRect()) + super.init(frame: .zero) self.lineWidth = lineWidth } /// Can init with a specific line thickness, scales based on width and height. @objc public init(lineThickness: CGFloat) { - super.init(frame: CGRect()) - self.lineThickness = lineThickness + super.init(frame: .zero) + // self.lineThickness = lineThickness + } + + @objc required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + fatalError("CaretView xib not supported.") } @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() { isOpaque = false isHidden = false @@ -65,34 +117,6 @@ open class CaretView: MFView { 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 @@ -102,10 +126,10 @@ open class CaretView: MFView { @objc open override func setAsMolecule() { defaultState() } - + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - // Configure class properties with JSON values + guard let dictionary = json else { return } if let strokeColorHex = dictionary["strokeColor"] as? String { @@ -115,7 +139,7 @@ open class CaretView: MFView { if let isHiddenValue = dictionary[KeyIsHidden] as? Bool { isHidden = isHiddenValue } - + if let isOpaqueValue = dictionary[KeyIsOpaque] as? Bool { isOpaque = isOpaqueValue } @@ -130,6 +154,6 @@ open class CaretView: MFView { } open override func alignment() -> UIStackView.Alignment { - return UIStackView.Alignment.leading; + return .leading } } diff --git a/MVMCoreUI/Atoms/Views/DashLine.swift b/MVMCoreUI/Atoms/Views/DashLine.swift index 9166ddfd..2bc11b98 100644 --- a/MVMCoreUI/Atoms/Views/DashLine.swift +++ b/MVMCoreUI/Atoms/Views/DashLine.swift @@ -31,7 +31,7 @@ open class DashLine: MFView { required public init?(coder: NSCoder) { super.init(coder: coder) - fatalError("DashLine xib not supported") +// fatalError("DashLine xib not supported") } //------------------------------------------------------