the latest.

This commit is contained in:
Kevin G Christiano 2019-10-28 15:51:03 -04:00
parent bf073d15e2
commit 9a578fc6b1
4 changed files with 127 additions and 138 deletions

View File

@ -16,6 +16,14 @@ import UIKit
private var calendar: Calendar? private var calendar: Calendar?
//--------------------------------------------------
// MARK: - Accessories
//--------------------------------------------------
public weak var datePicker: UIDatePicker?
public var pickerView: UIPickerView?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------

View File

@ -22,10 +22,10 @@ import UIKit
private(set) var fieldContainer: UIView? private(set) var fieldContainer: UIView?
private var borderStrokeColor: UIColor = UIColor.mfSilver() private var borderStrokeColor: UIColor = UIColor.mfSilver()
private var borderPath: UIBezierPath? private var borderPath: UIBezierPath = UIBezierPath()
public var bottomBar: UIView? public var bottomBar: UIView?
public var dashLine: DashLine? var delegateObject: MVMCoreUIDelegateObject?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
@ -38,13 +38,7 @@ import UIKit
public var hideBorder = false public var hideBorder = false
public var showErrorMessage = false public var showErrorMessage = false
public var errorMessage: String? { public var errorMessage: String?
didSet {
if showErrorMessage {
feedback = errorMessage
}
}
}
/// Toggles the enables state of this component. /// Toggles the enables state of this component.
public var isEnabled = true { public var isEnabled = true {
@ -52,12 +46,7 @@ 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 }
self.isUserInteractionEnabled = self.isEnabled self.isEnabled ? self.originalAppearance() : self.errorAppearance()
self.feedbackLabel?.text = nil
self.descriptionLabel?.textColor = self.isEnabled ? UIColor.mfBattleshipGrey() : UIColor.mfSilver()
self.bottomBar?.backgroundColor = self.isEnabled ? (self.showErrorMessage ? UIColor.mfPumpkin() : .black) : UIColor.mfSilver()
self.fieldContainer?.setNeedsDisplay()
self.fieldContainer?.layoutIfNeeded()
} }
} }
} }
@ -80,20 +69,13 @@ import UIKit
public var feedback: String? { public var feedback: String? {
get { return feedbackLabel?.text } get { return feedbackLabel?.text }
set { set {
DispatchQueue.main.async { [weak self] in self.feedbackLabel?.text = newValue
guard let self = self else { return } self.refreshUI()
self.feedbackLabel?.text = newValue
self.bottomBarHeightConstraint?.constant = self.showErrorMessage ? 4 : 1
self.bottomBar?.backgroundColor = self.showErrorMessage ? UIColor.mfPumpkin() : .black
self.setNeedsDisplay()
self.layoutIfNeeded()
}
setAccessibilityString(newValue) setAccessibilityString(newValue)
} }
} }
// TODO: Pull this out into Styler or some class akin to it.
public var formatter: DateFormatter = { public var formatter: DateFormatter = {
let formatter = DateFormatter() let formatter = DateFormatter()
@ -109,11 +91,11 @@ import UIKit
// MARK: - Constraints // MARK: - Constraints
//-------------------------------------------------- //--------------------------------------------------
public var textContainerLeading: NSLayoutConstraint? public var fieldContainerLeading: NSLayoutConstraint?
public var textContainerTrailing: NSLayoutConstraint? public var fieldContainerTrailing: NSLayoutConstraint?
public var errorLabelTrailing: NSLayoutConstraint? public var feedbackLabelTrailing: NSLayoutConstraint?
public var errorLabelLeading: NSLayoutConstraint? public var feedbackLabelLeading: NSLayoutConstraint?
public var descriptionLabelLeading: NSLayoutConstraint? public var descriptionLabelLeading: NSLayoutConstraint?
public var descriptionLabelTrailing: NSLayoutConstraint? public var descriptionLabelTrailing: NSLayoutConstraint?
@ -149,9 +131,8 @@ import UIKit
final public override func setupView() { final public override func setupView() {
guard subviews.isEmpty else { return } guard subviews.isEmpty else { return }
// heightAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
setContentHuggingPriority(.required, for: .vertical)
setContentCompressionResistancePriority(.required, for: .vertical) setContentCompressionResistancePriority(.required, for: .vertical)
backgroundColor = .clear backgroundColor = .clear
@ -159,9 +140,8 @@ import UIKit
self.descriptionLabel = descriptionLabel self.descriptionLabel = descriptionLabel
descriptionLabel.font = MFStyler.fontB3() descriptionLabel.font = MFStyler.fontB3()
descriptionLabel.textColor = UIColor.mfBattleshipGrey() descriptionLabel.textColor = UIColor.mfBattleshipGrey()
descriptionLabel.setContentHuggingPriority(UILayoutPriority(251), for: .horizontal)
descriptionLabel.setContentHuggingPriority(UILayoutPriority(251), for: .vertical)
descriptionLabel.setContentCompressionResistancePriority(.required, for: .vertical) descriptionLabel.setContentCompressionResistancePriority(.required, for: .vertical)
descriptionLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
addSubview(descriptionLabel) addSubview(descriptionLabel)
@ -179,35 +159,35 @@ import UIKit
setupFieldContainer(fieldContainer) setupFieldContainer(fieldContainer)
fieldContainer.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 4).isActive = true fieldContainer.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 4).isActive = true
textContainerLeading = fieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) fieldContainerLeading = fieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
textContainerLeading?.isActive = true fieldContainerLeading?.isActive = true
textContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor) fieldContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor)
textContainerTrailing?.isActive = true fieldContainerTrailing?.isActive = true
let feedbackLabel = Label() let feedbackLabel = Label()
self.feedbackLabel = feedbackLabel self.feedbackLabel = feedbackLabel
feedbackLabel.font = MFStyler.fontForTextFieldUnderLabel() feedbackLabel.font = MFStyler.fontForTextFieldUnderLabel()
feedbackLabel.textColor = .black feedbackLabel.textColor = .black
feedbackLabel.setContentHuggingPriority(UILayoutPriority(251), for: .horizontal)
feedbackLabel.setContentHuggingPriority(UILayoutPriority(251), for: .horizontal)
feedbackLabel.setContentCompressionResistancePriority(.required, for: .vertical) feedbackLabel.setContentCompressionResistancePriority(.required, for: .vertical)
feedbackLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
addSubview(feedbackLabel) addSubview(feedbackLabel)
feedbackLabel.topAnchor.constraint(equalTo: fieldContainer.bottomAnchor).isActive = true feedbackLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
errorLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) feedbackLabel.topAnchor.constraint(equalTo: fieldContainer.bottomAnchor, constant: PaddingOne).isActive = true
errorLabelLeading?.isActive = true feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
errorLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor) feedbackLabelLeading?.isActive = true
errorLabelTrailing?.isActive = true feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor)
feedbackLabelTrailing?.isActive = true
layoutMarginsGuide.bottomAnchor.constraint(equalTo: feedbackLabel.bottomAnchor).isActive = true layoutMarginsGuide.bottomAnchor.constraint(equalTo: feedbackLabel.bottomAnchor).isActive = true
setNeedsLayout() setNeedsLayout()
} }
/** /**
Method to override. Method to override.
Intended to add the interactive content (textField) to the fieldContainer. Intended to add the interactive content (textField) to the fieldContainer.
*/ */
open func setupFieldContainerContent(_ container: UIView) { open func setupFieldContainerContent(_ container: UIView) {
// To Be Overridden By Subclass. // To Be Overridden By Subclass.
} }
@ -229,19 +209,6 @@ import UIKit
bottomBar.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true bottomBar.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true
parentView.trailingAnchor.constraint(equalTo: bottomBar.trailingAnchor).isActive = true parentView.trailingAnchor.constraint(equalTo: bottomBar.trailingAnchor).isActive = true
parentView.bottomAnchor.constraint(equalTo: bottomBar.bottomAnchor).isActive = true parentView.bottomAnchor.constraint(equalTo: bottomBar.bottomAnchor).isActive = true
let dashLine = DashLine()
dashLine.translatesAutoresizingMaskIntoConstraints = false
dashLine.backgroundColor = .white
dashLine.isHidden = true
parentView.addSubview(dashLine)
NSLayoutConstraint.activate([
dashLine.centerYAnchor.constraint(equalTo: bottomBar.centerYAnchor),
dashLine.centerXAnchor.constraint(equalTo: bottomBar.centerXAnchor),
dashLine.topAnchor.constraint(equalTo: bottomBar.topAnchor),
dashLine.leadingAnchor.constraint(equalTo: bottomBar.leadingAnchor)])
} }
open override func updateView(_ size: CGFloat) { open override func updateView(_ size: CGFloat) {
@ -249,9 +216,8 @@ import UIKit
descriptionLabel?.updateView(size) descriptionLabel?.updateView(size)
feedbackLabel?.font = MFStyler.fontForTextFieldUnderLabel() feedbackLabel?.font = MFStyler.fontForTextFieldUnderLabel()
dashLine?.updateView(size)
layoutIfNeeded() refreshUI()
} }
//-------------------------------------------------- //--------------------------------------------------
@ -261,23 +227,22 @@ import UIKit
open override func draw(_ rect: CGRect) { open override func draw(_ rect: CGRect) {
super.draw(rect) super.draw(rect)
borderPath?.removeAllPoints() borderPath.removeAllPoints()
if !hideBorder, let frame = fieldContainer?.frame { if !hideBorder, let frame = fieldContainer?.frame {
// Brings the other half of the line inside the view to prevent thinness from cropping.
let insetLean: CGFloat = 0.5 let insetLean: CGFloat = 0.5
borderPath = UIBezierPath() borderPath.lineWidth = 1
borderPath?.lineWidth = 1
borderPath?.move(to: CGPoint(x: frame.origin.x + insetLean, y: frame.origin.y + frame.size.height)) borderPath.move(to: CGPoint(x: frame.origin.x + insetLean, y: frame.origin.y + frame.size.height))
borderPath?.addLine(to: CGPoint(x: frame.origin.x + insetLean, y: frame.origin.y + insetLean)) borderPath.addLine(to: CGPoint(x: frame.origin.x + insetLean, y: frame.origin.y + insetLean))
borderPath?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width - insetLean, y: frame.origin.y + insetLean)) borderPath.addLine(to: CGPoint(x: frame.origin.x + frame.size.width - insetLean, y: frame.origin.y + insetLean))
borderPath?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width - insetLean, y: frame.origin.y + frame.size.height)) borderPath.addLine(to: CGPoint(x: frame.origin.x + frame.size.width - insetLean, y: frame.origin.y + frame.size.height))
borderStrokeColor.setStroke() borderStrokeColor.setStroke()
borderPath.stroke()
borderPath?.stroke()
} }
} }
@ -287,15 +252,15 @@ import UIKit
open override func setLeftPinConstant(_ constant: CGFloat) { open override func setLeftPinConstant(_ constant: CGFloat) {
textContainerLeading?.constant = constant fieldContainerLeading?.constant = constant
errorLabelLeading?.constant = constant feedbackLabelLeading?.constant = constant
descriptionLabelLeading?.constant = constant descriptionLabelLeading?.constant = constant
} }
open override func setRightPinConstant(_ constant: CGFloat) { open override func setRightPinConstant(_ constant: CGFloat) {
textContainerTrailing?.constant = constant fieldContainerTrailing?.constant = constant
errorLabelTrailing?.constant = constant feedbackLabelTrailing?.constant = constant
descriptionLabelTrailing?.constant = constant descriptionLabelTrailing?.constant = constant
} }
@ -303,64 +268,82 @@ import UIKit
// MARK: - Form Appearance // MARK: - Form Appearance
//-------------------------------------------------- //--------------------------------------------------
public enum Appearance { public enum Appearance: String {
case original case original
case error case error
case locked case lock
case selected case select
case disabled
} }
/// Updates the visual appearance of the entry field. open func originalAppearance() {
public func fieldAppearance(_ state: Appearance) {
switch state { isUserInteractionEnabled = true
case .original: bottomBarHeightConstraint?.constant = 1
isUserInteractionEnabled = true hideBorder = false
borderStrokeColor = .mfSilver() showErrorMessage = false
bottomBar?.backgroundColor = .black borderStrokeColor = .mfSilver()
bottomBarHeightConstraint?.constant = 1 bottomBar?.backgroundColor = .black
descriptionLabel?.textColor = .mfBattleshipGrey()
case .error:
isUserInteractionEnabled = true refreshUI()
bottomBarHeightConstraint?.constant = 4 }
case .locked: open func errorAppearance(showError: Bool = false) {
isUserInteractionEnabled = false
hideBorder = true isUserInteractionEnabled = true
bottomBar?.backgroundColor = .clear hideBorder = false
bottomBarHeightConstraint?.constant = 1 bottomBarHeightConstraint?.constant = 4
borderStrokeColor = .mfPumpkin()
case .selected: bottomBar?.backgroundColor = .mfPumpkin()
isUserInteractionEnabled = true
borderStrokeColor = .mfSilver() if showError {
bottomBar?.backgroundColor = .black showErrorMessage = true
bottomBarHeightConstraint?.constant = 1 feedback = errorMessage
} }
fieldContainer?.setNeedsDisplay() refreshUI()
}
open func lockAppearance() {
isUserInteractionEnabled = false
bottomBarHeightConstraint?.constant = 1
hideBorder = true
bottomBar?.backgroundColor = .clear
refreshUI()
}
open func selectedAppearance() {
isUserInteractionEnabled = true
bottomBarHeightConstraint?.constant = 1
hideBorder = false
borderStrokeColor = .black
bottomBar?.backgroundColor = .black
refreshUI()
}
open func disabledAppearance() {
isUserInteractionEnabled = false
bottomBarHeightConstraint?.constant = 1
hideBorder = false
feedback = nil
descriptionLabel?.textColor = self.isEnabled ? UIColor.mfBattleshipGrey() : UIColor.mfSilver()
bottomBar?.backgroundColor = self.isEnabled ? (self.showErrorMessage ? UIColor.mfPumpkin() : .black) : UIColor.mfSilver()
refreshUI()
}
open func refreshUI() {
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self)
setNeedsDisplay()
layoutIfNeeded() layoutIfNeeded()
} }
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
open func showError(_ show: Bool) {
showErrorMessage = show
if show {
feedbackLabel?.text = errorMessage
fieldAppearance(.error)
}
}
open func showDashSeperatorView(_ dash: Bool) {
// Never hide seperator view because it could be possiblely used by other classes for positioning
dashLine?.isHidden = !dash
bottomBar?.backgroundColor = dash ? .clear : .black
}
} }
// MARK: - Molecular // MARK: - Molecular
@ -368,6 +351,7 @@ extension FormEntryField {
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
self.delegateObject = delegateObject
guard let dictionary = json, guard let dictionary = json,
!dictionary.isEmpty !dictionary.isEmpty
@ -389,6 +373,10 @@ extension FormEntryField {
self.hideBorder = hideBorder self.hideBorder = hideBorder
} }
if let appearance = dictionary["appearance"] as? String {
// let enu = Appearance(rawValue: appearance)
}
// Key used to send text value to server // Key used to send text value to server
if let fieldKey = dictionary[KeyFieldKey] as? String { if let fieldKey = dictionary[KeyFieldKey] as? String {
self.fieldKey = fieldKey self.fieldKey = fieldKey
@ -396,7 +384,7 @@ extension FormEntryField {
} }
override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 76 return 115
} }
} }

View File

@ -25,14 +25,6 @@ import UIKit
//-------------------------------------------------- //--------------------------------------------------
private(set) var textField: UITextField? private(set) var textField: UITextField?
private var calendar: Calendar?
//--------------------------------------------------
// MARK: - Accessories
//--------------------------------------------------
public weak var datePicker: UIDatePicker?
public var pickerView: UIPickerView?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Delegate Properties // MARK: - Delegate Properties
@ -173,8 +165,7 @@ import UIKit
} }
deinit { deinit {
mfTextFieldDelegate = nil setBothTextDelegates(nil)
uiTextFieldDelegate = nil
} }
//-------------------------------------------------- //--------------------------------------------------
@ -183,7 +174,7 @@ import UIKit
open func clearError() { open func clearError() {
feedback = nil // feedback = nil
textField?.accessibilityValue = nil textField?.accessibilityValue = nil
} }
@ -245,6 +236,7 @@ import UIKit
func startEditing() { func startEditing() {
errorAppearance(showError: true)
textField?.becomeFirstResponder() textField?.becomeFirstResponder()
} }
} }

View File

@ -25,12 +25,13 @@ open class DashLine: MFView {
super.init(frame: .zero) super.init(frame: .zero)
} }
public init() { public convenience init() {
super.init(frame: .zero) self.init(frame: .zero)
} }
required public init?(coder: NSCoder) { required public init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
fatalError("DashLine xib not supported")
} }
//------------------------------------------------------ //------------------------------------------------------