Merge branch 'feature/toolbar_entry_field' into 'release/7_6_0'

Toolbar entry field

See merge request BPHV_MIPS/mvm_core_ui!376
This commit is contained in:
Suresh, Kamlesh Jain 2020-04-20 18:33:01 -04:00
commit 07d19f6a2c
28 changed files with 362 additions and 158 deletions

View File

@ -94,6 +94,7 @@
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */; }; 0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */; };
0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */; }; 0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */; };
0A7ECC702441001C00C828E8 /* UIToolbar+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC6F2441001C00C828E8 /* UIToolbar+Extension.swift */; };
0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */; }; 0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */; };
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */; }; 0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */; };
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */; }; 0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */; };
@ -102,6 +103,8 @@
0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; }; 0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; };
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; }; 0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; };
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; };
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */; };
0AB764D324460FA400E7FE72 /* UIPickerView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D224460FA400E7FE72 /* UIPickerView+Extension.swift */; };
0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */; }; 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */; };
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; }; 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; };
0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; }; 0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; };
@ -518,6 +521,7 @@
0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxLabel.swift; sourceTree = "<group>"; }; 0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxLabel.swift; sourceTree = "<group>"; };
0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoughnutChartItemModel.swift; sourceTree = "<group>"; }; 0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoughnutChartItemModel.swift; sourceTree = "<group>"; };
0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorViewWithLabel.swift; sourceTree = "<group>"; }; 0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorViewWithLabel.swift; sourceTree = "<group>"; };
0A7ECC6F2441001C00C828E8 /* UIToolbar+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIToolbar+Extension.swift"; sourceTree = "<group>"; };
0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryFieldModel.swift; sourceTree = "<group>"; }; 0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryFieldModel.swift; sourceTree = "<group>"; };
0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryFieldModel.swift; sourceTree = "<group>"; }; 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryFieldModel.swift; sourceTree = "<group>"; };
0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryFieldModel.swift; sourceTree = "<group>"; }; 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryFieldModel.swift; sourceTree = "<group>"; };
@ -528,6 +532,8 @@
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = "<group>"; }; 0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = "<group>"; };
0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; }; 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; };
0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = "<group>"; }; 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = "<group>"; };
0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Extension.swift"; sourceTree = "<group>"; };
0AB764D224460FA400E7FE72 /* UIPickerView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIPickerView+Extension.swift"; sourceTree = "<group>"; };
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = "<group>"; }; 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = "<group>"; };
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = "<group>"; }; 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = "<group>"; };
0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; }; 0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
@ -1114,6 +1120,9 @@
D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */, D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */,
D202AFE5242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift */, D202AFE5242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift */,
013F801823FB4A8E00AD8013 /* UIContentMode+Extension.swift */, 013F801823FB4A8E00AD8013 /* UIContentMode+Extension.swift */,
0A7ECC6F2441001C00C828E8 /* UIToolbar+Extension.swift */,
0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */,
0AB764D224460FA400E7FE72 /* UIPickerView+Extension.swift */,
); );
path = Extensions; path = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2184,6 +2193,7 @@
BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */, BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */,
D2B18B812360945C00A9AEDC /* View.swift in Sources */, D2B18B812360945C00A9AEDC /* View.swift in Sources */,
C6FA7D5423C77A4A00A3614A /* NumberedList.swift in Sources */, C6FA7D5423C77A4A00A3614A /* NumberedList.swift in Sources */,
0A7ECC702441001C00C828E8 /* UIToolbar+Extension.swift in Sources */,
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
525019E52406852100EED91C /* ListFourColumnDataUsageDividerModel.swift in Sources */, 525019E52406852100EED91C /* ListFourColumnDataUsageDividerModel.swift in Sources */,
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */, 0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */,
@ -2284,6 +2294,7 @@
012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */, 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */,
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
0AE14F64238315D2005417F8 /* TextField.swift in Sources */, 0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */, D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */,
C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */, C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */,
@ -2364,6 +2375,7 @@
8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */, 8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */,
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */, D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */,
012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */, 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */,
0AB764D324460FA400E7FE72 /* UIPickerView+Extension.swift in Sources */,
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
94C661D923CCF4B400D9FE5B /* LeftRightLabelModel.swift in Sources */, 94C661D923CCF4B400D9FE5B /* LeftRightLabelModel.swift in Sources */,
011D95AB2405C553000E3791 /* FormItemProtocol.swift in Sources */, 011D95AB2405C553000E3791 /* FormItemProtocol.swift in Sources */,

View File

@ -9,6 +9,7 @@
import UIKit import UIKit
@objcMembers public class ActionCollapseNotificationModel: ActionModelProtocol { @objcMembers public class ActionCollapseNotificationModel: ActionModelProtocol {
public static var identifier: String = "collapseNotification" public static var identifier: String = "collapseNotification"
public var actionType: String public var actionType: String
public var extraParameters: JSONValueDictionary? public var extraParameters: JSONValueDictionary?

View File

@ -9,7 +9,7 @@
import Foundation import Foundation
public class ActionOpenPanelModel: ActionModelProtocol { public class ActionOpenPanelModel: ActionModelProtocol {
public enum Panel: String, Codable { public enum Panel: String, Codable {
case left case left
case right case right

View File

@ -9,6 +9,7 @@
import Foundation import Foundation
@objcMembers public class ActionTopAlertModel: ActionModelProtocol { @objcMembers public class ActionTopAlertModel: ActionModelProtocol {
public static var identifier: String = "topAlert" public static var identifier: String = "topAlert"
public var actionType: String = ActionTopAlertModel.identifier public var actionType: String = ActionTopAlertModel.identifier
public var pageType: String public var pageType: String

View File

@ -69,7 +69,7 @@ import UIKit
textFieldTrailingConstraint = dropDownCaretView.leadingAnchor.constraint(equalTo: textField.trailingAnchor, constant: 6) textFieldTrailingConstraint = dropDownCaretView.leadingAnchor.constraint(equalTo: textField.trailingAnchor, constant: 6)
textFieldTrailingConstraint?.isActive = true textFieldTrailingConstraint?.isActive = true
container.trailingAnchor.constraint(equalTo: dropDownCaretView.trailingAnchor, constant: 16).isActive = true container.trailingAnchor.constraint(equalTo: dropDownCaretView.trailingAnchor, constant: Padding.Four).isActive = true
dropDownCaretView.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true dropDownCaretView.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
} }

View File

@ -31,10 +31,9 @@ import UIKit
return formatter return formatter
}() }()
/// Update the property value to alter the format of how the date is presented.
public var dateFormat: String = "MMM d, y" { public var dateFormat: String = "MMM d, y" {
didSet { didSet { dateFormatter.dateFormat = dateFormat }
dateFormatter.dateFormat = dateFormat
}
} }
//-------------------------------------------------- //--------------------------------------------------
@ -69,10 +68,10 @@ import UIKit
public override func setupFieldContainerContent(_ container: UIView) { public override func setupFieldContainerContent(_ container: UIView) {
super.setupFieldContainerContent(container) super.setupFieldContainerContent(container)
datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField) datePicker = UIDatePicker.addDatePicker(to: textField)
datePicker?.addTarget(self, action: #selector(pickerValueChanged), for: .valueChanged) datePicker?.addTarget(self, action: #selector(pickerValueChanged), for: .valueChanged)
datePicker?.timeZone = NSTimeZone.system datePicker?.timeZone = NSTimeZone.system
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: self) UIToolbar.addDismissToolbar(to: textField, delegate: self, action: #selector(dismissFieldInput))
} }
@objc public func setDatePickerDuration(from startDate: Date?, to endDate: Date?, showStartDate: Bool = true) { @objc public func setDatePickerDuration(from startDate: Date?, to endDate: Date?, showStartDate: Bool = true) {
@ -104,7 +103,7 @@ import UIKit
} }
} }
@objc override func dismissFieldInput(_ sender: Any?) { @objc public override func dismissFieldInput(_ sender: Any?) {
setTextWith(date: datePicker?.date) setTextWith(date: datePicker?.date)
super.dismissFieldInput(sender) super.dismissFieldInput(sender)

View File

@ -22,24 +22,25 @@
//-------------------------------------------------- //--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName
case dateFormat case dateFormat
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Codec
//-------------------------------------------------- //--------------------------------------------------
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
try super.init(from: decoder) try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
dateFormat = try typeContainer.decodeIfPresent(String.self, forKey: .dateFormat) ?? "MMM d, y"
if let dateFormat = try typeContainer.decodeIfPresent(String.self, forKey: .dateFormat) {
self.dateFormat = dateFormat
}
} }
public override func encode(to encoder: Encoder) throws { public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder) try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(dateFormat, forKey: .dateFormat) try container.encode(dateFormat, forKey: .dateFormat)
} }
} }

View File

@ -211,7 +211,9 @@ import UIKit
let digitBox = DigitBox() let digitBox = DigitBox()
digitBox.isAccessibilityElement = true digitBox.isAccessibilityElement = true
digitBox.digitField.inputAccessoryView = MVMCoreUICommonViewsUtility.getToolbarWithDoneButton(delegate: self) let observingDelegate = delegateObject?.observingTextFieldDelegate ?? self
digitBox.digitField.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate,
action: #selector(observingDelegate.dismissFieldInput))
digitBox.digitField.delegate = self digitBox.digitField.delegate = self
digitBox.digitBoxDelegate = self digitBox.digitBoxDelegate = self
return digitBox return digitBox
@ -246,15 +248,6 @@ import UIKit
} }
} }
@objc public override func defaultValidationBlock() {
validationBlock = { enteredValue in
guard let enteredValue = enteredValue else { return false }
return enteredValue.count > 0 && enteredValue.count == self.digitBoxes.count
}
}
@objc public func selectPreviousDigitField(_ currentTextField: UITextField?, clear: Bool) { @objc public func selectPreviousDigitField(_ currentTextField: UITextField?, clear: Bool) {
var selectPreviousField = false var selectPreviousField = false
@ -322,7 +315,7 @@ import UIKit
return true return true
} }
@objc override func dismissFieldInput(_ sender: Any?) { @objc public override func dismissFieldInput(_ sender: Any?) {
digitBoxes.forEach { digitBoxes.forEach {
if $0.isSelected { if $0.isSelected {
@ -337,12 +330,18 @@ import UIKit
guard let model = model as? DigitEntryFieldModel else { return } guard let model = model as? DigitEntryFieldModel else { return }
numberOfDigits = model.digits numberOfDigits = model.digits
setAsSecureTextEntry(model.secureEntry)
for digitBox in digitBoxes { if let entryType = model.type {
digitBox.digitField.inputAccessoryView = MVMCoreUICommonViewsUtility.getToolbarWithDoneButton(delegate: delegateObject?.observingTextFieldDelegate ?? self) setAsSecureTextEntry(entryType == .secure || entryType == .password)
} }
let observingDelegate = delegateObject?.observingTextFieldDelegate ?? self
digitBoxes.forEach {
$0.digitField.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate,
action: #selector(observingDelegate.dismissFieldInput))
}
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
} }

View File

@ -17,34 +17,31 @@
} }
public var digits: Int = 4 public var digits: Int = 4
public var secureEntry: Bool = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Keys // MARK: - Keys
//-------------------------------------------------- //--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName
case digits case digits
case secureEntry
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Codec
//-------------------------------------------------- //--------------------------------------------------
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
try super.init(from: decoder) try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
digits = try typeContainer.decodeIfPresent(Int.self, forKey: .digits) ?? 4
secureEntry = try typeContainer.decodeIfPresent(Bool.self, forKey: .secureEntry) ?? false if let digits = try typeContainer.decodeIfPresent(Int.self, forKey: .digits) {
self.digits = digits
}
} }
public override func encode(to encoder: Encoder) throws { public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder) try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(digits, forKey: .digits) try container.encode(digits, forKey: .digits)
try container.encode(secureEntry, forKey: .secureEntry)
} }
} }

View File

@ -20,7 +20,7 @@ import UIKit
public private(set) var titleLabel: Label = { public private(set) var titleLabel: Label = {
let label = Label() let label = Label()
label.font = MFStyler.fontRegularMicro() label.font = Styler.Font.RegularMicro.getFont()
label.textColor = .mvmBlack label.textColor = .mvmBlack
label.setContentCompressionResistancePriority(.required, for: .vertical) label.setContentCompressionResistancePriority(.required, for: .vertical)
return label return label
@ -31,12 +31,12 @@ import UIKit
/// Provides contextual information on the TextField. /// Provides contextual information on the TextField.
public private(set) var feedbackLabel: Label = { public private(set) var feedbackLabel: Label = {
let label = Label() let label = Label()
label.font = MFStyler.fontRegularMicro() label.font = Styler.Font.RegularMicro.getFont()
label.textColor = .mvmBlack label.textColor = .mvmBlack
label.setContentCompressionResistancePriority(.required, for: .vertical) label.setContentCompressionResistancePriority(.required, for: .vertical)
return label return label
}() }()
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Delegate // MARK: - Delegate
//-------------------------------------------------- //--------------------------------------------------
@ -48,14 +48,6 @@ import UIKit
//-------------------------------------------------- //--------------------------------------------------
public var isValid: Bool = false public var isValid: Bool = false
public var errorMessage: String?
public var standardMessage: String? {
didSet {
if !showError {
feedback = standardMessage
}
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Computed Properties // MARK: - Computed Properties
@ -75,7 +67,7 @@ import UIKit
public var showError: Bool { public var showError: Bool {
get { return entryFieldContainer.showError } get { return entryFieldContainer.showError }
set (error) { set (error) {
self.feedback = error ? self.errorMessage : self.standardMessage self.feedback = error ? entryFieldModel?.errorMessage : entryFieldModel?.feedback
self.entryFieldContainer.showError = error self.entryFieldContainer.showError = error
} }
} }
@ -121,6 +113,10 @@ import UIKit
} }
} }
public var entryFieldModel: EntryFieldModel? {
return model as? EntryFieldModel
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Constraints // MARK: - Constraints
//-------------------------------------------------- //--------------------------------------------------
@ -174,8 +170,6 @@ import UIKit
@objc final public override func setupView() { @objc final public override func setupView() {
super.setupView() super.setupView()
guard subviews.isEmpty else { return }
isAccessibilityElement = false isAccessibilityElement = false
setContentCompressionResistancePriority(.required, for: .vertical) setContentCompressionResistancePriority(.required, for: .vertical)
accessibilityElements = [titleLabel, feedbackLabel] accessibilityElements = [titleLabel, feedbackLabel]
@ -193,7 +187,7 @@ import UIKit
entryFieldContainer.setContentCompressionResistancePriority(.required, for: .vertical) entryFieldContainer.setContentCompressionResistancePriority(.required, for: .vertical)
setupFieldContainerContent(entryFieldContainer) setupFieldContainerContent(entryFieldContainer)
titleContainerDistance = entryFieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4) titleContainerDistance = entryFieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: Padding.One)
titleContainerDistance?.isActive = true titleContainerDistance?.isActive = true
entryFieldContainerLeading = entryFieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) entryFieldContainerLeading = entryFieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
entryFieldContainerLeading?.isActive = true entryFieldContainerLeading?.isActive = true
@ -202,7 +196,7 @@ import UIKit
addSubview(feedbackLabel) addSubview(feedbackLabel)
feedbackContainerDistance = feedbackLabel.topAnchor.constraint(equalTo: entryFieldContainer.bottomAnchor, constant: PaddingOne) feedbackContainerDistance = feedbackLabel.topAnchor.constraint(equalTo: entryFieldContainer.bottomAnchor, constant: Padding.Two)
feedbackContainerDistance?.isActive = true feedbackContainerDistance?.isActive = true
feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
feedbackLabelLeading?.isActive = true feedbackLabelLeading?.isActive = true
@ -217,11 +211,11 @@ import UIKit
entryFieldContainer.refreshUI() entryFieldContainer.refreshUI()
} }
/// Method to override. /**
/// Intended to add the interactive content (i.e. textField) to the entryFieldContainer. Method to override.
@objc open func setupFieldContainerContent(_ container: UIView) { Intended to add the interactive content (i.e. textField) to the entryFieldContainer.
// To be overridden by subclass. */
} @objc open func setupFieldContainerContent(_ container: UIView) { }
@objc open override func updateView(_ size: CGFloat) { @objc open override func updateView(_ size: CGFloat) {
super.updateView(size) super.updateView(size)
@ -240,10 +234,11 @@ import UIKit
backgroundColor = .clear backgroundColor = .clear
isAccessibilityElement = false isAccessibilityElement = false
titleLabel.font = MFStyler.fontRegularMicro() titleLabel.font = Styler.Font.RegularMicro.getFont()
titleLabel.textColor = .mvmBlack titleLabel.textColor = .mvmBlack
feedbackLabel.font = MFStyler.fontRegularMicro() feedbackLabel.font = Styler.Font.RegularMicro.getFont()
feedbackLabel.textColor = .mvmBlack feedbackLabel.textColor = .mvmBlack
feedbackLabel.text = nil
entryFieldContainer.reset() entryFieldContainer.reset()
} }
@ -257,7 +252,6 @@ import UIKit
title = model.title title = model.title
feedback = model.feedback feedback = model.feedback
errorMessage = model.errorMessage
isEnabled = model.enabled isEnabled = model.enabled
if let isLocked = model.locked { if let isLocked = model.locked {

View File

@ -22,29 +22,22 @@ import Foundation
public var backgroundColor: Color? public var backgroundColor: Color?
public var title: String? public var title: String?
public var feedback: String? public var feedback: String?
public var errorMessage: String = "" public var errorMessage: String?
public var enabled: Bool = true public var enabled: Bool = true
public var locked: Bool? public var locked: Bool?
public var selected: Bool? public var selected: Bool?
public var text: String? public var text: String?
public var fieldKey: String? public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable? public var baseValue: AnyHashable?
public var isValid: Bool? { public var isValid: Bool? {
didSet { didSet { updateUI?() }
updateUI?()
}
} }
/// Temporary binding mechanism for the view to update on enable changes. /// Temporary binding mechanism for the view to update on enable changes.
public var updateUI: (() -> Void)? public var updateUI: (() -> ())?
public func setValidity(_ valid: Bool, rule: RulesProtocol) {
self.isValid = valid
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Keys // MARK: - Keys
//-------------------------------------------------- //--------------------------------------------------
@ -62,11 +55,19 @@ import Foundation
case fieldKey case fieldKey
case groupName case groupName
} }
//--------------------------------------------------
// MARK: - Validation Methods
//--------------------------------------------------
public func formFieldValue() -> AnyHashable? { public func formFieldValue() -> AnyHashable? {
return text return text
} }
public func setValidity(_ valid: Bool, rule: RulesProtocol) {
self.isValid = valid
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
@ -76,17 +77,20 @@ import Foundation
baseValue = text baseValue = text
} }
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
title = try typeContainer.decodeIfPresent(String.self, forKey: .title) title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback) feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback)
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage) ?? "" errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage)
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked) locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked)
selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected)
text = try typeContainer.decodeIfPresent(String.self, forKey: .text) text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
baseValue = text baseValue = text
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
@ -100,11 +104,11 @@ import Foundation
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(title, forKey: .title) try container.encodeIfPresent(title, forKey: .title)
try container.encodeIfPresent(feedback, forKey: .feedback) try container.encodeIfPresent(feedback, forKey: .feedback)
try container.encode(errorMessage, forKey: .errorMessage)
try container.encode(enabled, forKey: .enabled)
try container.encode(locked, forKey: .locked)
try container.encode(selected, forKey: .selected)
try container.encodeIfPresent(text, forKey: .text) try container.encodeIfPresent(text, forKey: .text)
try container.encodeIfPresent(locked, forKey: .locked)
try container.encodeIfPresent(selected, forKey: .selected)
try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
try container.encode(enabled, forKey: .enabled)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName) try container.encodeIfPresent(groupName, forKey: .groupName)
} }

View File

@ -8,6 +8,8 @@
import UIKit import UIKit
public typealias TextFieldAndPickerDelegate = (UITextFieldDelegate & UIPickerViewDelegate & UIPickerViewDataSource)
open class ItemDropdownEntryField: BaseDropdownEntryField { open class ItemDropdownEntryField: BaseDropdownEntryField {
//-------------------------------------------------- //--------------------------------------------------
@ -62,7 +64,7 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
@objc open override func setupFieldContainerContent(_ container: UIView) { @objc open override func setupFieldContainerContent(_ container: UIView) {
super.setupFieldContainerContent(container) super.setupFieldContainerContent(container)
pickerView = MVMCoreUICommonViewsUtility.addPicker(to: textField, delegate: self) pickerView = UIPickerView.addPicker(to: textField, delegate: self, dismissAction: #selector(dismissFieldInput))
textField.hideBlinkingCaret = true textField.hideBlinkingCaret = true
textField.autocorrectionType = .no textField.autocorrectionType = .no
uiTextFieldDelegate = self uiTextFieldDelegate = self

View File

@ -23,7 +23,6 @@
//-------------------------------------------------- //--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName
case options case options
case selectedIndex case selectedIndex
} }
@ -35,14 +34,17 @@
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
try super.init(from: decoder) try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
options = try typeContainer.decode([String].self, forKey: .options) options = try typeContainer.decode([String].self, forKey: .options)
selectedIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) ?? 0
if let selectedIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) {
self.selectedIndex = selectedIndex
}
} }
public override func encode(to encoder: Encoder) throws { public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder) try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(options, forKey: .options) try container.encode(options, forKey: .options)
try container.encode(options, forKey: .selectedIndex) try container.encode(options, forKey: .selectedIndex)
} }

View File

@ -48,6 +48,18 @@ import MVMCore
set { text = MVMCoreUIUtility.formatMdn(newValue) } set { text = MVMCoreUIUtility.formatMdn(newValue) }
} }
/// Toggles selected or original (unselected) UI.
public override var isSelected: Bool {
get { return entryFieldContainer.isSelected }
set (selected) {
if selected && showError {
showError = false
}
super.isSelected = selected
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
@ -77,11 +89,14 @@ import MVMCore
super.setupFieldContainerContent(container) super.setupFieldContainerContent(container)
textField.keyboardType = .numberPad textField.keyboardType = .numberPad
}
open override func setupTextFieldToolbar() {
let toolbar = MVMCoreUICommonViewsUtility.makeEmptyToolbar() let toolbar = UIToolbar.createEmptyToolbar()
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let contacts = UIBarButtonItem(title: MVMCoreUIUtility.hardcodedString(withKey: "textfield_contacts_barbutton"), style: .plain, target: self, action: #selector(getContacts(_:))) let contacts = UIBarButtonItem(title: MVMCoreUIUtility.hardcodedString(withKey: "textfield_contacts_barbutton"), style: .plain, target: self, action: #selector(getContacts))
let dismissButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissFieldInput(_:))) let dismissButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissFieldInput))
toolbar.items = [contacts, space, dismissButton] toolbar.items = [contacts, space, dismissButton]
textField.inputAccessoryView = toolbar textField.inputAccessoryView = toolbar
} }
@ -107,18 +122,18 @@ import MVMCore
isValid = true isValid = true
return true return true
} }
let isValid = hasValidMDN() isValid = hasValidMDN()
if isValid { if self.isValid {
showError = false showError = false
} else { } else {
errorMessage = errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message") entryFieldModel?.errorMessage = entryFieldModel?.errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
showError = true showError = true
UIAccessibility.post(notification: .layoutChanged, argument: textField) UIAccessibility.post(notification: .layoutChanged, argument: textField)
} }
return isValid return isValid
} }
@ -196,7 +211,7 @@ import MVMCore
} }
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { @objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true return proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
} }

View File

@ -15,7 +15,7 @@ import UIKit
/// Called when the entered text becomes invalid based on the validation block /// Called when the entered text becomes invalid based on the validation block
@objc optional func isInvalid(textfield: TextEntryField?) @objc optional func isInvalid(textfield: TextEntryField?)
/// Dismisses the keyboard. /// Dismisses the keyboard.
@objc optional func dismissFieldInput(sender: Any?) @objc optional func dismissFieldInput(_ sender: Any?)
} }
@ -28,7 +28,7 @@ import UIKit
let textField = TextField() let textField = TextField()
textField.isAccessibilityElement = true textField.isAccessibilityElement = true
textField.setContentCompressionResistancePriority(.required, for: .vertical) textField.setContentCompressionResistancePriority(.required, for: .vertical)
textField.font = MFStyler.fontRegularBodyLarge() textField.font = Styler.Font.RegularBodyLarge.getFont()
textField.textColor = .mvmBlack textField.textColor = .mvmBlack
textField.smartQuotesType = .no textField.smartQuotesType = .no
textField.smartDashesType = .no textField.smartDashesType = .no
@ -36,13 +36,19 @@ import UIKit
return textField return textField
}() }()
public lazy var errorImage: UIImageView = {
let image = MVMCoreUIUtility.imageNamed("alert_standard")
let imageView = UIImageView(image: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
return imageView
}()
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Stored Properties // MARK: - Stored Properties
//-------------------------------------------------- //--------------------------------------------------
/// Set enabled and disabled colors to be utilized when setting this texfield's isEnabled property.
public var textColor: (enabled: UIColor?, disabled: UIColor?) = (.mvmBlack, .mvmCoolGray3)
private var observingForChange: Bool = false private var observingForChange: Bool = false
/// Validate on each entry in the textField. Default: true /// Validate on each entry in the textField. Default: true
@ -54,7 +60,7 @@ import UIKit
public var textEntryFieldModel: TextEntryFieldModel? { public var textEntryFieldModel: TextEntryFieldModel? {
return model as? TextEntryFieldModel return model as? TextEntryFieldModel
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Computed Properties // MARK: - Computed Properties
//-------------------------------------------------- //--------------------------------------------------
@ -68,7 +74,7 @@ import UIKit
guard let self = self else { return } guard let self = self else { return }
self.textField.isEnabled = enabled self.textField.isEnabled = enabled
self.textField.textColor = enabled ? self.textColor.enabled : self.textColor.disabled self.textField.textColor = enabled ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor
} }
} }
} }
@ -78,11 +84,15 @@ import UIKit
set (error) { set (error) {
if error { if error {
textField.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", textField.text ?? "", errorMessage ?? "") textField.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", textField.text ?? "", entryFieldModel?.errorMessage ?? "")
} else { } else {
textField.accessibilityValue = nil textField.accessibilityValue = nil
} }
if textField.isSecureTextEntry {
showErrorView(error)
}
super.showError = error super.showError = error
} }
} }
@ -102,12 +112,6 @@ import UIKit
set { textField.placeholder = newValue } set { textField.placeholder = newValue }
} }
//--------------------------------------------------
// MARK: - Property Observers
//--------------------------------------------------
public var validationBlock: ((_ value: String?) -> Bool)?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Delegate Properties // MARK: - Delegate Properties
//-------------------------------------------------- //--------------------------------------------------
@ -169,21 +173,21 @@ import UIKit
@objc open override func setupFieldContainerContent(_ container: UIView) { @objc open override func setupFieldContainerContent(_ container: UIView) {
textField.font = MFStyler.fontRegularBodyLarge() textField.font = Styler.Font.RegularBodyLarge.getFont()
container.addSubview(textField) container.addSubview(textField)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
textField.heightAnchor.constraint(equalToConstant: 24), textField.heightAnchor.constraint(equalToConstant: Padding.Five),
textField.topAnchor.constraint(equalTo: container.topAnchor, constant: 12), textField.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three),
textField.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 16), textField.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three),
container.bottomAnchor.constraint(equalTo: textField.bottomAnchor, constant: 12) container.bottomAnchor.constraint(equalTo: textField.bottomAnchor, constant: Padding.Three)
]) ])
textFieldTrailingConstraint = container.trailingAnchor.constraint(equalTo: textField.trailingAnchor, constant: 16) textFieldTrailingConstraint = container.trailingAnchor.constraint(equalTo: textField.trailingAnchor, constant: Padding.Three)
textFieldTrailingConstraint?.isActive = true textFieldTrailingConstraint?.isActive = true
textField.addTarget(self, action: #selector(startEditing), for: .editingDidBegin) textField.addTarget(self, action: #selector(startEditing), for: .editingDidBegin)
textField.addTarget(self, action: #selector(dismissFieldInput(_:)), for: .editingDidEnd) textField.addTarget(self, action: #selector(dismissFieldInput), for: .editingDidEnd)
let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing))
entryFieldContainer.addGestureRecognizer(tap) entryFieldContainer.addGestureRecognizer(tap)
@ -194,37 +198,31 @@ import UIKit
@objc open override func updateView(_ size: CGFloat) { @objc open override func updateView(_ size: CGFloat) {
super.updateView(size) super.updateView(size)
textField.font = MFStyler.fontRegularBodyLarge() textField.font = Styler.Font.RegularBodyLarge.getFont()
layoutIfNeeded() layoutIfNeeded()
} }
open override func reset() { open override func reset() {
super.reset() super.reset()
textField.font = MFStyler.fontRegularBodyLarge() textField.font = Styler.Font.RegularBodyLarge.getFont()
} }
@objc deinit {
setBothTextDelegates(to: nil)
}
@objc public func setBothTextDelegates(to delegate: (UITextFieldDelegate & ObservingTextFieldDelegate)?) { @objc public func setBothTextDelegates(to delegate: (UITextFieldDelegate & ObservingTextFieldDelegate)?) {
observingTextFieldDelegate = delegate observingTextFieldDelegate = delegate
uiTextFieldDelegate = delegate uiTextFieldDelegate = delegate
} }
open func setupTextFieldToolbar() {
let observingDelegate = observingTextFieldDelegate ?? self
textField.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate,
action: #selector(observingDelegate.dismissFieldInput))
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Observing for Change (TextFieldDelegate) // MARK: - Observing for Change (TextFieldDelegate)
//-------------------------------------------------- //--------------------------------------------------
public func defaultValidationBlock() {
validationBlock = { enteredValue in
guard let enteredValue = enteredValue else { return false }
return enteredValue.count > 0
}
}
@discardableResult @discardableResult
@objc override open func resignFirstResponder() -> Bool { @objc override open func resignFirstResponder() -> Bool {
if validateWhenDoneEditing { if validateWhenDoneEditing {
@ -240,11 +238,11 @@ import UIKit
text = textField.text text = textField.text
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
} }
@objc public func updateValidation(_ isValid: Bool) { @objc public func updateValidation(_ isValid: Bool) {
let previousValidity = self.isValid let previousValidity = self.isValid
self.isValid = isValid self.isValid = isValid
if previousValidity && !isValid { if previousValidity && !isValid {
showError = true showError = true
observingTextFieldDelegate?.isInvalid?(textfield: self) observingTextFieldDelegate?.isInvalid?(textfield: self)
@ -276,10 +274,30 @@ import UIKit
} }
} }
@objc func dismissFieldInput(_ sender: Any?) { @objc public func dismissFieldInput(_ sender: Any?) {
resignFirstResponder() resignFirstResponder()
} }
private func showErrorView(_ show: Bool) {
if show {
entryFieldContainer.addSubview(errorImage)
textFieldTrailingConstraint?.isActive = false
textFieldTrailingConstraint = errorImage.leadingAnchor.constraint(equalTo: textField.trailingAnchor, constant: Padding.Two)
textFieldTrailingConstraint?.isActive = true
entryFieldContainer.trailingAnchor.constraint(equalTo: errorImage.trailingAnchor, constant: Padding.Three).isActive = true
errorImage.centerYAnchor.constraint(equalTo: entryFieldContainer.centerYAnchor).isActive = true
} else {
errorImage.removeFromSuperview()
textFieldTrailingConstraint?.isActive = false
textFieldTrailingConstraint = entryFieldContainer.trailingAnchor.constraint(equalTo: textField.trailingAnchor, constant: Padding.Two)
textFieldTrailingConstraint?.isActive = true
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - MoleculeViewProtocol // MARK: - MoleculeViewProtocol
//-------------------------------------------------- //--------------------------------------------------
@ -288,37 +306,39 @@ import UIKit
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
guard let model = model as? TextEntryFieldModel else { return } guard let model = model as? TextEntryFieldModel else { return }
model.updateUI = { [weak self] in model.updateUI = { [weak self] in
MVMCoreDispatchUtility.performBlock(onMainThread: { MVMCoreDispatchUtility.performBlock(onMainThread: {
if self?.isSelected ?? false { guard let self = self else { return }
self?.updateValidation(model.isValid ?? true)
if self.isSelected {
self.updateValidation(model.isValid ?? true)
} }
}) })
} }
self.delegateObject = delegateObject self.delegateObject = delegateObject
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
textColor.enabled = model.enabledTextColor?.uiColor
textColor.disabled = model.disabledTextColor?.uiColor
text = model.text text = model.text
placeholder = model.placeholder placeholder = model.placeholder
switch model.type { switch model.type {
case .password: case .password, .secure:
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
case .number: case .number:
textField.keyboardType = .numberPad textField.keyboardType = .numberPad
case .email: case .email:
textField.keyboardType = .emailAddress textField.keyboardType = .emailAddress
default: default:
break break
} }
defaultValidationBlock()
uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate
observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate
textField.inputAccessoryView = MVMCoreUICommonViewsUtility.getToolbarWithDoneButton(delegate: observingTextFieldDelegate ?? self) setupTextFieldToolbar()
} }
} }

View File

@ -8,9 +8,13 @@
@objcMembers public class TextEntryFieldModel: EntryFieldModel { @objcMembers public class TextEntryFieldModel: EntryFieldModel {
//--------------------------------------------------
// MARK: - Types
//--------------------------------------------------
public enum EntryType: String, Codable { public enum EntryType: String, Codable {
case password case password
case secure
case number case number
case email case email
} }
@ -24,8 +28,8 @@
} }
public var placeholder: String? public var placeholder: String?
public var enabledTextColor: Color? public var enabledTextColor: Color = Color(uiColor: .mvmBlack)
public var disabledTextColor: Color? public var disabledTextColor: Color = Color(uiColor: .mvmCoolGray3)
public var type: EntryType? public var type: EntryType?
//-------------------------------------------------- //--------------------------------------------------
@ -34,7 +38,6 @@
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName case moleculeName
case text
case placeholder case placeholder
case enabledTextColor case enabledTextColor
case disabledTextColor case disabledTextColor
@ -42,27 +45,31 @@
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Codec
//-------------------------------------------------- //--------------------------------------------------
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
try super.init(from: decoder) try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .placeholder) placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .placeholder)
enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor)
disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor)
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type) type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type)
if let enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor) {
self.enabledTextColor = enabledTextColor
}
if let disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor) {
self.disabledTextColor = disabledTextColor
}
} }
public override func encode(to encoder: Encoder) throws { public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder) try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(text, forKey: .text)
try container.encodeIfPresent(placeholder, forKey: .placeholder) try container.encodeIfPresent(placeholder, forKey: .placeholder)
try container.encodeIfPresent(enabledTextColor, forKey: .enabledTextColor) try container.encode(enabledTextColor, forKey: .enabledTextColor)
try container.encodeIfPresent(disabledTextColor, forKey: .disabledTextColor) try container.encode(disabledTextColor, forKey: .disabledTextColor)
try container.encodeIfPresent(type, forKey: .type) try container.encodeIfPresent(type, forKey: .type)
} }
} }

View File

@ -0,0 +1,37 @@
//
// UIDatePicker+Extension.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 4/14/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public extension UIDatePicker {
class func addDatePicker(to textField: UITextField) -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.backgroundColor = .mvmWhite
datePicker.datePickerMode = .date
let locale = NSLocale.current as NSLocale
datePicker.locale = locale as Locale
datePicker.calendar = locale.object(forKey: .calendar) as? Calendar
textField.inputView = datePicker
return datePicker
}
class func addTimeAndDatePicker(to textField: UITextField) -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.backgroundColor = .mvmWhite
datePicker.datePickerMode = .time
textField.inputView = datePicker
return datePicker
}
}

View File

@ -0,0 +1,38 @@
//
// UIPickerView.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 4/14/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public extension UIPickerView {
class func createPickerView() -> UIPickerView {
let picker = UIPickerView(frame: .zero)
picker.backgroundColor = .mvmWhite
picker.showsSelectionIndicator = true
return picker
}
class func addPicker(to textField: UITextField, delegate: TextFieldAndPickerDelegate?, dismissAction: Selector?) -> UIPickerView {
// Sets up the picker (same tag as the textfield)
let picker = createPickerView()
picker.delegate = delegate
picker.dataSource = delegate
picker.tag = textField.tag
textField.inputView = picker
// Adds a dismiss toolbar, since all fields with pickers should have one.
if let dismissAction = dismissAction {
UIToolbar.addDismissToolbar(to: textField, delegate: delegate, action: dismissAction)
}
return picker
}
}

View File

@ -0,0 +1,56 @@
//
// UIToolbar+Extension.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 4/10/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol TextFieldOrView { }
extension UITextView: TextFieldOrView { }
extension UITextField: TextFieldOrView { }
public extension UIToolbar {
class func createEmptyToolbar() -> UIToolbar {
let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44))
toolbar.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleWidth]
toolbar.barStyle = .default
toolbar.barTintColor = .mvmCoolGray3
toolbar.tintColor = .mvmBlack
toolbar.isTranslucent = true
return toolbar
}
class func getToolbarWithDoneButton(delegate: Any?, action: Selector) -> UIToolbar {
let toolbar = createEmptyToolbar()
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let button = UIBarButtonItem(barButtonSystemItem: .done, target: delegate, action: action)
toolbar.setItems([space, button], animated: false)
return toolbar
}
class func addDismissToolbar(to object: TextFieldOrView, delegate: Any?, action: Selector) {
let toolbar = Self.getToolbarWithDoneButton(delegate: delegate, action: action)
switch object {
case is UITextField:
(object as? UITextField)?.inputAccessoryView = toolbar
case is UITextView:
(object as? UITextView)?.inputAccessoryView = toolbar
default:
return
}
}
}

View File

@ -36,7 +36,7 @@ open class ScrollingViewController: ViewController {
super.viewDidLoad() super.viewDidLoad()
// Adds the tap gesture to dismiss the keyboard. // Adds the tap gesture to dismiss the keyboard.
dismissKeyboardTapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissFieldInput(sender:))) dismissKeyboardTapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissFieldInput))
view.addGestureRecognizer(dismissKeyboardTapGesture!) view.addGestureRecognizer(dismissKeyboardTapGesture!)
dismissKeyboardTapGesture?.isEnabled = false dismissKeyboardTapGesture?.isEnabled = false
scrollView.alwaysBounceVertical = false scrollView.alwaysBounceVertical = false

View File

@ -405,7 +405,7 @@ import UIKit
} }
} }
@objc open func dismissFieldInput(sender: Any?) { @objc open func dismissFieldInput(_ sender: Any?) {
selectedField?.resignFirstResponder() selectedField?.resignFirstResponder()
} }

View File

@ -25,9 +25,7 @@ import UIKit
/// Total control over the drawn top, bottom, left and right borders. /// Total control over the drawn top, bottom, left and right borders.
public var disableAllBorders = false { public var disableAllBorders = false {
didSet { didSet { bottomBar?.isHidden = disableAllBorders }
bottomBar?.isHidden = disableAllBorders
}
} }
private(set) var fieldState: FieldState = .original { private(set) var fieldState: FieldState = .original {

View File

@ -10,10 +10,8 @@ import Foundation
open class Styler { open class Styler {
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
// MARK:- Font Enum
public enum Font: String, Codable { public enum Font: String, Codable {
case Title2XLarge case Title2XLarge
case TitleXLarge case TitleXLarge

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "alert_standard @1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "alert_standard @2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "alert_standard @3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

View File

@ -14,7 +14,7 @@ public extension MVMCoreUICommonViewsUtility {
let toolbar = self.makeEmptyToolbar() let toolbar = self.makeEmptyToolbar()
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let button = UIBarButtonItem(barButtonSystemItem: .done, target: delegate, action: #selector(ObservingTextFieldDelegate.dismissFieldInput(sender:))) let button = UIBarButtonItem(barButtonSystemItem: .done, target: delegate, action: #selector(ObservingTextFieldDelegate.dismissFieldInput))
button.tintColor = .black button.tintColor = .black
toolbar.setItems([space, button], animated: false) toolbar.setItems([space, button], animated: false)