Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/viewInRoomArAtomicTemplate
This commit is contained in:
commit
28cb8ed94a
@ -62,6 +62,8 @@
|
||||
01EB369323609801006832FA /* HeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368C23609801006832FA /* HeaderModel.swift */; };
|
||||
01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368D23609801006832FA /* HeadlineBodyModel.swift */; };
|
||||
01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */; };
|
||||
0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */; };
|
||||
0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */; };
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
||||
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */; };
|
||||
0A21DB7F235DECC500C160A2 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB7E235DECC500C160A2 /* EntryField.swift */; };
|
||||
@ -94,7 +96,7 @@
|
||||
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */; };
|
||||
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */; };
|
||||
0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86023D8AC2500B2AAD1 /* DigitEntryFieldModel.swift */; };
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; };
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift */; };
|
||||
0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; };
|
||||
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; };
|
||||
0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */; };
|
||||
@ -114,6 +116,8 @@
|
||||
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; };
|
||||
0AD93A9F24C0AA5100E56A97 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7918F423F5E7EA00772FF4 /* ImageView.swift */; };
|
||||
0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; };
|
||||
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */; };
|
||||
0AE277EC25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */; };
|
||||
0AE98BAF23FEF956004C5109 /* ExternalLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BAE23FEF956004C5109 /* ExternalLink.swift */; };
|
||||
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */; };
|
||||
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
|
||||
@ -612,6 +616,8 @@
|
||||
01EB368C23609801006832FA /* HeaderModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderModel.swift; sourceTree = "<group>"; };
|
||||
01EB368D23609801006832FA /* HeadlineBodyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyModel.swift; sourceTree = "<group>"; };
|
||||
01F2A03123A4498200D954D8 /* CaretLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaretLinkModel.swift; sourceTree = "<group>"; };
|
||||
0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryField.swift; sourceTree = "<group>"; };
|
||||
0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
||||
0A209CD223A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackViewAlignment+Extension.swift"; sourceTree = "<group>"; };
|
||||
0A21DB7E235DECC500C160A2 /* EntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = "<group>"; };
|
||||
@ -645,7 +651,7 @@
|
||||
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>"; };
|
||||
0A7EF86023D8AC2500B2AAD1 /* DigitEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = "<group>"; };
|
||||
@ -666,6 +672,8 @@
|
||||
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>"; };
|
||||
0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||
0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0AE98BAE23FEF956004C5109 /* ExternalLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLink.swift; sourceTree = "<group>"; };
|
||||
0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLinkModel.swift; sourceTree = "<group>"; };
|
||||
0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = "<group>"; };
|
||||
@ -1183,6 +1191,39 @@
|
||||
path = FormUIHelpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A0FEC7125D4246000AF2548 /* Dropdown Fields */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift */,
|
||||
0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */,
|
||||
0A0FEC8D25D4487F00AF2548 /* Date Dropdown */,
|
||||
0A0FEC8A25D4486F00AF2548 /* Item Dropdown */,
|
||||
);
|
||||
path = "Dropdown Fields";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A0FEC8A25D4486F00AF2548 /* Item Dropdown */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */,
|
||||
0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */,
|
||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */,
|
||||
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */,
|
||||
0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */,
|
||||
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */,
|
||||
);
|
||||
path = "Item Dropdown";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A0FEC8D25D4487F00AF2548 /* Date Dropdown */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */,
|
||||
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */,
|
||||
);
|
||||
path = "Date Dropdown";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A5D59C323AD488600EFD9E9 /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -2060,14 +2101,9 @@
|
||||
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */,
|
||||
0A7EF86023D8AC2500B2AAD1 /* DigitEntryFieldModel.swift */,
|
||||
0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */,
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */,
|
||||
0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */,
|
||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */,
|
||||
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */,
|
||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */,
|
||||
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */,
|
||||
0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */,
|
||||
0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */,
|
||||
0A0FEC7125D4246000AF2548 /* Dropdown Fields */,
|
||||
);
|
||||
path = TextFields;
|
||||
sourceTree = "<group>";
|
||||
@ -2473,6 +2509,7 @@
|
||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
||||
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
|
||||
0AE277EC25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift in Sources */,
|
||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
|
||||
3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */,
|
||||
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */,
|
||||
@ -2487,6 +2524,7 @@
|
||||
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
|
||||
94382086243238D100B43AF3 /* WebViewModel.swift in Sources */,
|
||||
D28764F9245A327200CB882D /* TwoLinkView.swift in Sources */,
|
||||
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEntryField.swift in Sources */,
|
||||
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */,
|
||||
0A6682B5243769C700AD3CA1 /* TextView.swift in Sources */,
|
||||
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
|
||||
@ -2587,6 +2625,7 @@
|
||||
D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */,
|
||||
014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */,
|
||||
AAC23FAF24D92A1E009208DF /* ListThreeColumnSpeedTest.swift in Sources */,
|
||||
0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */,
|
||||
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
||||
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
||||
D2ED27ED254B0CE700A1C293 /* ActionPopupModel.swift in Sources */,
|
||||
@ -2702,6 +2741,7 @@
|
||||
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
||||
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
|
||||
323AC96C24C837FF00F8E4C4 /* ListThreeColumnBillChanges.swift in Sources */,
|
||||
0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */,
|
||||
D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */,
|
||||
D2351C7C24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift in Sources */,
|
||||
017BEB7B236763000024EF95 /* LineModel.swift in Sources */,
|
||||
@ -2889,7 +2929,7 @@
|
||||
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */,
|
||||
BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */,
|
||||
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */,
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */,
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift in Sources */,
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */,
|
||||
D236E5B5241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift in Sources */,
|
||||
D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */,
|
||||
|
||||
@ -11,12 +11,14 @@ import UIKit
|
||||
public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?)
|
||||
|
||||
|
||||
public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol, EnableableModelProtocol {
|
||||
open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "button"
|
||||
//Making static property as class property so that subclasses can override getter function of the property
|
||||
open class var identifier: String {
|
||||
"button"
|
||||
}
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String
|
||||
@ -247,7 +249,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(title, forKey: .title)
|
||||
|
||||
@ -80,7 +80,7 @@ import UIKit
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
|
||||
addSubview(digitField)
|
||||
digitField.delegate = self
|
||||
digitField.didDeleteDelegate = self
|
||||
@ -140,7 +140,7 @@ import UIKit
|
||||
super.updateView(size)
|
||||
|
||||
if !MVMCoreGetterUtility.fequal(a: Float(size), b: Float(previousSize)) {
|
||||
|
||||
|
||||
var width: CGFloat = 0
|
||||
var height: CGFloat = 0
|
||||
var pointSize: CGFloat = 13
|
||||
|
||||
@ -75,7 +75,7 @@ import UIKit
|
||||
private var selectedDigitBox: DigitBox?
|
||||
|
||||
public var digitEntryModel: DigitEntryFieldModel? {
|
||||
return model as? DigitEntryFieldModel
|
||||
model as? DigitEntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -83,7 +83,7 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
get { return super.isEnabled }
|
||||
get { super.isEnabled }
|
||||
set (enabled) {
|
||||
digitBoxes.forEach { $0.isEnabled = enabled }
|
||||
super.isEnabled = enabled
|
||||
@ -91,7 +91,7 @@ import UIKit
|
||||
}
|
||||
|
||||
public override var showError: Bool {
|
||||
get { return super.showError }
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
digitBoxes.forEach { $0.showError = error }
|
||||
super.showError = error
|
||||
@ -99,7 +99,7 @@ import UIKit
|
||||
}
|
||||
|
||||
public override var isLocked: Bool {
|
||||
get { return super.isLocked }
|
||||
get { super.isLocked }
|
||||
set (locked) {
|
||||
digitBoxes.forEach { $0.isLocked = locked }
|
||||
super.isLocked = locked
|
||||
@ -162,7 +162,7 @@ import UIKit
|
||||
|
||||
/// If you're using a MFViewController, you must set this to it
|
||||
public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||
get { return textField.delegate }
|
||||
get { textField.delegate }
|
||||
set {
|
||||
textField.delegate = self
|
||||
proprietorTextDelegate = newValue
|
||||
@ -450,11 +450,11 @@ extension DigitEntryField {
|
||||
|
||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||
proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||
proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
public override class var identifier: String { "digitTextField" }
|
||||
|
||||
public var digits: Int = 4
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// BaseDropdownEntryField.swift
|
||||
// BaseDropdownField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 10/23/19.
|
||||
@ -28,8 +28,9 @@ import UIKit
|
||||
}()
|
||||
|
||||
public var baseDropdownEntryFieldModel: BaseDropdownEntryFieldModel? {
|
||||
return model as? BaseDropdownEntryFieldModel
|
||||
model as? BaseDropdownEntryFieldModel
|
||||
}
|
||||
|
||||
var additionalData: [AnyHashable: Any]?
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -54,7 +55,7 @@ import UIKit
|
||||
|
||||
@objc required public init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
fatalError("DropdownEntryField does not support xib.")
|
||||
fatalError("\(String(describing: Self.self)) does not support xib.")
|
||||
}
|
||||
|
||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
@ -86,10 +87,10 @@ import UIKit
|
||||
dropDownCaretView.setOptional(with: model.caretView, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
public override func dismissFieldInput(_ sender: Any?) {
|
||||
performDropdownAction()
|
||||
super.dismissFieldInput(sender)
|
||||
}
|
||||
@objc public override func dismissFieldInput(_ sender: Any?) {
|
||||
performDropdownAction()
|
||||
super.dismissFieldInput(sender)
|
||||
}
|
||||
|
||||
func performDropdownAction() {
|
||||
if let baseDropdownEntryFieldModel = baseDropdownEntryFieldModel, let actionModel = baseDropdownEntryFieldModel.action {
|
||||
@ -27,7 +27,7 @@
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
@ -69,6 +69,7 @@ import UIKit
|
||||
datePicker = UIDatePicker.addDatePicker(to: textField)
|
||||
datePicker?.addTarget(self, action: #selector(pickerValueChanged), for: .valueChanged)
|
||||
datePicker?.timeZone = NSTimeZone.system
|
||||
textField.inputView = datePicker
|
||||
UIToolbar.addDismissToolbar(to: textField, delegate: self, action: #selector(dismissFieldInput))
|
||||
}
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
//
|
||||
// BaseItemPickerEntryField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/10/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public typealias TextFieldAndPickerDelegate = (UITextFieldDelegate & UIPickerViewDelegate & UIPickerViewDataSource)
|
||||
|
||||
|
||||
open class BaseItemPickerEntryField: BaseDropdownEntryField, UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
open lazy var pickerView = UIPickerView.addPicker(to: textField, delegate: self, dismissAction: #selector(dismissFieldInput))
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Closure passed here will run as picker changes items.
|
||||
public var observeDropdownChange: ((String, String) -> ())?
|
||||
|
||||
/// Closure passed here will run upon dismissing the selection picker.
|
||||
public var observeDropdownSelection: ((String) -> ())?
|
||||
|
||||
/// When selecting for first responder, allow initial selected value to appear in empty text field.
|
||||
public var setInitialValueInTextField = true
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
||||
super.setupFieldContainerContent(container)
|
||||
|
||||
textField.hideBlinkingCaret = true
|
||||
textField.autocorrectionType = .no
|
||||
uiTextFieldDelegate = self
|
||||
}
|
||||
|
||||
@objc public func setPickerDelegates(delegate: UIPickerViewDelegate & UIPickerViewDataSource) {
|
||||
|
||||
pickerView.delegate = delegate
|
||||
pickerView.dataSource = delegate
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Molecular
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
setPickerDelegates(delegate: self)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Picker Delegate to Override
|
||||
//--------------------------------------------------
|
||||
|
||||
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 0 }
|
||||
|
||||
public func numberOfComponents(in pickerView: UIPickerView) -> Int { 0 }
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Accessibility
|
||||
extension BaseItemPickerEntryField {
|
||||
|
||||
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
|
||||
|
||||
var accessibilityString = accessibilityString ?? ""
|
||||
|
||||
if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
||||
accessibilityString += textPickerItem
|
||||
}
|
||||
|
||||
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
//
|
||||
// BaseItemPickerEntryFieldModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/10/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
open class BaseItemPickerEntryFieldModel: BaseDropdownEntryFieldModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String { "" }
|
||||
}
|
||||
@ -8,28 +8,16 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
public typealias TextFieldAndPickerDelegate = (UITextFieldDelegate & UIPickerViewDelegate & UIPickerViewDataSource)
|
||||
|
||||
|
||||
open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
open class ItemDropdownEntryField: BaseItemPickerEntryField {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open var pickerData: [String] = []
|
||||
open var pickerView: UIPickerView?
|
||||
|
||||
/// When selecting for first responder, allow initial selected value to appear in empty text field.
|
||||
public var setInitialValueInTextField = true
|
||||
|
||||
/// Closure passed here will run as picker changes items.
|
||||
public var observeDropdownChange: ((String, String)->())?
|
||||
|
||||
/// Closure passed here will run upon dismissing the selection picker.
|
||||
public var observeDropdownSelection: ((String)->())?
|
||||
|
||||
public var itemDropdownEntryFieldModel: ItemDropdownEntryFieldModel? {
|
||||
return model as? ItemDropdownEntryFieldModel
|
||||
model as? ItemDropdownEntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -61,26 +49,13 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
||||
super.setupFieldContainerContent(container)
|
||||
|
||||
pickerView = UIPickerView.addPicker(to: textField, delegate: self, dismissAction: #selector(dismissFieldInput))
|
||||
textField.hideBlinkingCaret = true
|
||||
textField.autocorrectionType = .no
|
||||
uiTextFieldDelegate = self
|
||||
}
|
||||
|
||||
@objc public func setPickerDelegates(delegate: UIPickerViewDelegate & UIPickerViewDataSource) {
|
||||
|
||||
pickerView?.delegate = delegate
|
||||
pickerView?.dataSource = delegate
|
||||
}
|
||||
|
||||
/// Sets the textField with the first value of the available picker data.
|
||||
@objc private func setInitialValueFromPicker() {
|
||||
|
||||
guard !pickerData.isEmpty else { return }
|
||||
|
||||
if setInitialValueInTextField, let pickerIndex = pickerView?.selectedRow(inComponent: 0) {
|
||||
if setInitialValueInTextField {
|
||||
let pickerIndex = pickerView.selectedRow(inComponent: 0)
|
||||
observeDropdownChange?(text ?? "", pickerData[pickerIndex])
|
||||
text = pickerData[pickerIndex]
|
||||
itemDropdownEntryFieldModel?.selectedIndex = pickerIndex
|
||||
@ -98,9 +73,7 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
|
||||
guard !pickerData.isEmpty else { return }
|
||||
|
||||
if let pickerIndex = pickerView?.selectedRow(inComponent: 0) {
|
||||
observeDropdownSelection?(pickerData[pickerIndex])
|
||||
}
|
||||
observeDropdownSelection?(pickerData[pickerView.selectedRow(inComponent: 0)])
|
||||
}
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
@ -109,20 +82,20 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
guard let model = model as? ItemDropdownEntryFieldModel else { return }
|
||||
|
||||
pickerData = model.options
|
||||
setPickerDelegates(delegate: self)
|
||||
|
||||
if let pickerView = pickerView, let index = model.selectedIndex {
|
||||
if let index = model.selectedIndex {
|
||||
self.pickerView.selectRow(index, inComponent: 0, animated: false)
|
||||
self.pickerView(pickerView, didSelectRow: index, inComponent: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK:- Base Picker Delegate
|
||||
extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Picker Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 }
|
||||
@objc public override func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 }
|
||||
|
||||
@objc public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
@objc public override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
pickerData.count
|
||||
}
|
||||
|
||||
@ -140,18 +113,3 @@ extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
itemDropdownEntryFieldModel?.selectedIndex = row
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Accessibility
|
||||
extension ItemDropdownEntryField {
|
||||
|
||||
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
|
||||
|
||||
var accessibilityString = accessibilityString ?? ""
|
||||
|
||||
if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
||||
accessibilityString += textPickerItem
|
||||
}
|
||||
|
||||
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
@objcMembers open class ItemDropdownEntryFieldModel: BaseDropdownEntryFieldModel {
|
||||
@objcMembers open class ItemDropdownEntryFieldModel: BaseItemPickerEntryFieldModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -15,11 +15,15 @@
|
||||
|
||||
public var options: [String] = []
|
||||
public var selectedIndex: Int?
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func formFieldValue() -> AnyHashable? {
|
||||
guard !options.isEmpty,
|
||||
let index = selectedIndex
|
||||
else { return nil }
|
||||
let index = selectedIndex
|
||||
else { return nil }
|
||||
|
||||
return options[index]
|
||||
}
|
||||
@ -32,7 +36,7 @@
|
||||
case options
|
||||
case selectedIndex
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
@ -45,10 +49,7 @@
|
||||
|
||||
if let selectedIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) {
|
||||
self.selectedIndex = selectedIndex
|
||||
}
|
||||
|
||||
if let index = selectedIndex {
|
||||
baseValue = options.indices.contains(index) ? options[index] : nil
|
||||
baseValue = options.indices.contains(selectedIndex) ? options[selectedIndex] : nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,144 @@
|
||||
//
|
||||
// MultiItemDropdownEndryField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/9/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
open class MultiItemDropdownEntryField: BaseItemPickerEntryField {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Datasource of the picker view.
|
||||
open var pickerComponents: [[String]] {
|
||||
dropdownModel?.components ?? [[]]
|
||||
}
|
||||
|
||||
public var dropdownModel: MultiItemDropdownEntryFieldModel? {
|
||||
model as? MultiItemDropdownEntryFieldModel
|
||||
}
|
||||
|
||||
/// The number of components available
|
||||
public var componentCount: Int {
|
||||
pickerComponents.count
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
@objc public convenience init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
@objc required public init?(coder: NSCoder) {
|
||||
fatalError("MultiItemDropdownEntryField init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.init(model: model, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Sets the textField with the first value of the available picker data.
|
||||
@objc private func setInitialValueFromPicker() {
|
||||
|
||||
guard setInitialValueInTextField,
|
||||
!pickerComponents.isEmpty,
|
||||
let rowText = dropdownModel?.selectedRowText
|
||||
else { return }
|
||||
|
||||
// Update observing function and update text UI.
|
||||
observeDropdownChange?(text ?? "", rowText)
|
||||
text = rowText
|
||||
|
||||
// Set row index value of selected component.
|
||||
for component in 0..<componentCount {
|
||||
let pickerIndex = pickerView.selectedRow(inComponent: component)
|
||||
dropdownModel?.selectedIndexes[component] = pickerIndex
|
||||
}
|
||||
}
|
||||
|
||||
func pickerHasComponent(_ index: Int) -> Bool {
|
||||
!pickerComponents.isEmpty && !pickerComponents[index].isEmpty
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - TextField Observation
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Observing action of the textfield for initial interaction with the picker.
|
||||
@objc override func startEditing() {
|
||||
super.startEditing()
|
||||
|
||||
setInitialValueFromPicker()
|
||||
}
|
||||
|
||||
/// Observing action for when the user has ended inputting with the picker.
|
||||
@objc override func endInputing() {
|
||||
super.endInputing()
|
||||
|
||||
guard !pickerComponents.isEmpty,
|
||||
let rowText = dropdownModel?.selectedRowText
|
||||
else { return }
|
||||
|
||||
// update observing function with most recent selection.
|
||||
observeDropdownSelection?(rowText)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? MultiItemDropdownEntryFieldModel else { return }
|
||||
|
||||
// Select initial rows if selectedIndexes retains value.
|
||||
for (component, row) in model.selectedIndexes {
|
||||
self.pickerView.selectRow(row, inComponent: component, animated: false)
|
||||
self.pickerView(pickerView, didSelectRow: row, inComponent: component)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Picker Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public override func numberOfComponents(in pickerView: UIPickerView) -> Int { componentCount }
|
||||
|
||||
@objc public override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
pickerComponents[component].count
|
||||
}
|
||||
|
||||
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||
|
||||
guard pickerHasComponent(component) else { return nil }
|
||||
|
||||
return pickerComponents[component][row]
|
||||
}
|
||||
|
||||
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
||||
|
||||
guard pickerHasComponent(component) else { return }
|
||||
|
||||
let oldText = text ?? ""
|
||||
dropdownModel?.selectedIndexes[component] = row
|
||||
let newText = dropdownModel?.selectedRowText
|
||||
observeDropdownChange?(oldText, newText ?? "")
|
||||
text = newText
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
//
|
||||
// MultiItemDropdownEntryFieldModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/9/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
@objcMembers open class MultiItemDropdownEntryFieldModel: BaseItemPickerEntryFieldModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String { "multiDropdown" }
|
||||
|
||||
public var components: [[String]] = [[]]
|
||||
public var selectedIndexes: [Int: Int] = [:]
|
||||
public var delimiters: [Int: String] = [:]
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func formFieldValue() -> AnyHashable? {
|
||||
|
||||
guard !components.isEmpty && !selectedIndexes.isEmpty else { return nil }
|
||||
|
||||
return selectedRowText
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// - parameter index: The index of the delimiter.
|
||||
/// - returns: The delimiter for a given index. Defaults to whitespace for valid index if no delimiters is provided. If invalid index, empty string.
|
||||
public func delimiter(for index: Int) -> String {
|
||||
|
||||
guard index != components.count - 1 else { return "" }
|
||||
|
||||
return delimiters[index, default: " "]
|
||||
}
|
||||
|
||||
/// A string of the picker row concatenated by whitespace or delimiters if provided.
|
||||
public var selectedRowText: String {
|
||||
|
||||
var text = ""
|
||||
|
||||
for i in 0..<components.count {
|
||||
let pickerIndex = selectedIndexes[i] ?? 0
|
||||
text += components[i][pickerIndex] + delimiter(for: i)
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
public var selectedIndexesArray: [Int] {
|
||||
|
||||
var indexArray: [Int] = []
|
||||
|
||||
for i in 0..<selectedIndexes.count {
|
||||
guard let selectIndex = selectedIndexes[i] else { return [] }
|
||||
indexArray.append(selectIndex)
|
||||
}
|
||||
|
||||
return indexArray
|
||||
}
|
||||
|
||||
public var delimiterArray: [String] {
|
||||
|
||||
var array: [String] = []
|
||||
|
||||
for i in 0..<delimiters.count {
|
||||
guard let delimiterIndex = delimiters[i] else { return [] }
|
||||
array.append(delimiterIndex)
|
||||
}
|
||||
|
||||
return array
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case components
|
||||
case selectedIndexes
|
||||
case delimiters
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
try super.init(from: decoder)
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
components = try typeContainer.decode([[String]].self, forKey: .components)
|
||||
|
||||
if let delimiters = try typeContainer.decodeIfPresent([String].self, forKey: .delimiters) {
|
||||
for (index, delimiter) in delimiters.enumerated() {
|
||||
self.delimiters[index] = delimiter
|
||||
}
|
||||
}
|
||||
|
||||
if let indexes = try typeContainer.decodeIfPresent([Int].self, forKey: .selectedIndexes) {
|
||||
for (component, index) in indexes.enumerated() {
|
||||
self.selectedIndexes[component] = index
|
||||
}
|
||||
|
||||
baseValue = selectedRowText
|
||||
}
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(components, forKey: .components)
|
||||
try container.encode(selectedIndexesArray, forKey: .selectedIndexes)
|
||||
try container.encodeIfPresent(delimiterArray, forKey: .delimiters)
|
||||
}
|
||||
}
|
||||
@ -36,7 +36,7 @@ import UIKit
|
||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Delegate
|
||||
//--------------------------------------------------
|
||||
@ -58,23 +58,23 @@ import UIKit
|
||||
|
||||
/// Toggles enabled (original) or disabled UI.
|
||||
public var isEnabled: Bool {
|
||||
get { return entryFieldContainer.isEnabled }
|
||||
get { entryFieldContainer.isEnabled }
|
||||
set (enabled) {
|
||||
self.titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
self.feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
self.entryFieldContainer.isEnabled = enabled
|
||||
self.entryFieldModel?.enabled = enabled
|
||||
titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
entryFieldContainer.isEnabled = enabled
|
||||
entryFieldModel?.enabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggles error or original UI.
|
||||
public var showError: Bool {
|
||||
get { return entryFieldContainer.showError }
|
||||
get { entryFieldContainer.showError }
|
||||
set (error) {
|
||||
self.feedback = error ? errorMessage : entryFieldModel?.feedback
|
||||
self.feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack
|
||||
self.entryFieldContainer.showError = error
|
||||
self.entryFieldModel?.showError = error
|
||||
feedback = error ? errorMessage : entryFieldModel?.feedback
|
||||
feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack
|
||||
entryFieldContainer.showError = error
|
||||
entryFieldModel?.showError = error
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,49 +84,48 @@ import UIKit
|
||||
|
||||
/// Toggles original or locked UI.
|
||||
public var isLocked: Bool {
|
||||
get { return entryFieldContainer.isLocked }
|
||||
get { entryFieldContainer.isLocked }
|
||||
set (locked) {
|
||||
self.entryFieldContainer.isLocked = locked
|
||||
self.entryFieldModel?.locked = locked
|
||||
entryFieldContainer.isLocked = locked
|
||||
entryFieldModel?.locked = locked
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggles selected or original (unselected) UI.
|
||||
public var isSelected: Bool {
|
||||
get { return entryFieldContainer.isSelected }
|
||||
get { entryFieldContainer.isSelected }
|
||||
set (selected) {
|
||||
self.entryFieldContainer.isSelected = selected
|
||||
self.entryFieldModel?.selected = selected
|
||||
entryFieldContainer.isSelected = selected
|
||||
entryFieldModel?.selected = selected
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the text of titleLabel
|
||||
public var title: String? {
|
||||
get { return titleLabel.text }
|
||||
set (newText) {
|
||||
titleLabel.text = newText
|
||||
setAccessibilityString(newText)
|
||||
get { titleLabel.text }
|
||||
set {
|
||||
titleLabel.text = newValue
|
||||
setAccessibilityString(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// Override this to conveniently get/set the textfield(s).
|
||||
public var text: String? {
|
||||
get { return nil }
|
||||
get { nil }
|
||||
set { fatalError("You MUST override EntryField's 'text' variable in your subclass.") }
|
||||
}
|
||||
|
||||
/// Sets feedback text in the textField.
|
||||
public var feedback: String? {
|
||||
get { return feedbackLabel.text }
|
||||
set (newFeedback) {
|
||||
feedbackLabel.text = newFeedback
|
||||
get { feedbackLabel.text }
|
||||
set {
|
||||
feedbackLabel.text = newValue
|
||||
feedbackLabel.accessibilityElementsHidden = feedbackLabel.text?.isEmpty ?? true
|
||||
entryFieldContainer.refreshUI(updateMoleculeLayout: true)
|
||||
}
|
||||
}
|
||||
|
||||
public var entryFieldModel: EntryFieldModel? {
|
||||
return model as? EntryFieldModel
|
||||
model as? EntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -223,7 +222,7 @@ import UIKit
|
||||
entryFieldContainer.refreshUI()
|
||||
}
|
||||
|
||||
/// Intended to add the interactive content (i.e. textField) to the entryFieldContainer.
|
||||
/// Intended to add the interactive content (i.e. textField) to the entryFieldContainer.
|
||||
@objc open func setupFieldContainerContent(_ container: UIView) {
|
||||
// To Be Overriden
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ import Foundation
|
||||
|
||||
/// Temporary binding mechanism for the view to update on enable changes.
|
||||
public var updateUI: ActionBlock?
|
||||
|
||||
|
||||
// TODO: Remove once updateUI is fixed with isSelected
|
||||
public var updateUIDynamicError: ActionBlock?
|
||||
|
||||
@ -140,9 +140,9 @@ import Foundation
|
||||
try container.encodeIfPresent(selected, forKey: .selected)
|
||||
try container.encodeIfPresent(errorTextColor, forKey: .errorTextColor)
|
||||
try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(hideBorders, forKey: .hideBorders)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(hideBorders, forKey: .hideBorders)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ import MVMCore
|
||||
|
||||
/// If you're using a MFViewController, you must set this to it
|
||||
public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||
get { return textField.delegate }
|
||||
get { textField.delegate }
|
||||
set {
|
||||
textField.delegate = self
|
||||
proprietorTextDelegate = newValue
|
||||
@ -44,7 +44,7 @@ import MVMCore
|
||||
|
||||
/// Formats the MDN when setting and removes format of MDN when reading.
|
||||
public var mdn: String? {
|
||||
get { return MVMCoreUIUtility.removeMdnFormat(text) }
|
||||
get { MVMCoreUIUtility.removeMdnFormat(text) }
|
||||
set { text = MVMCoreUIUtility.formatMdn(newValue) }
|
||||
}
|
||||
|
||||
@ -160,9 +160,9 @@ import MVMCore
|
||||
|
||||
// Sometimes user add extra 1 in front of mdn in their address book
|
||||
if isNationalMDN,
|
||||
let unformedMDN = unformattedMDN,
|
||||
unformedMDN.count == 11,
|
||||
unformedMDN[(unformedMDN.index(unformedMDN.startIndex, offsetBy: 0))] == "1" {
|
||||
let unformedMDN = unformattedMDN,
|
||||
unformedMDN.count == 11,
|
||||
unformedMDN[(unformedMDN.index(unformedMDN.startIndex, offsetBy: 0))] == "1" {
|
||||
|
||||
let startIndex = unformedMDN.index(unformedMDN.startIndex, offsetBy: 1)
|
||||
unformattedMDN = String(unformedMDN[startIndex...])
|
||||
|
||||
@ -61,7 +61,7 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
get { return super.isEnabled }
|
||||
get { super.isEnabled }
|
||||
set (enabled) {
|
||||
super.isEnabled = enabled
|
||||
|
||||
@ -75,7 +75,7 @@ import UIKit
|
||||
}
|
||||
|
||||
public override var showError: Bool {
|
||||
get { return super.showError }
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
|
||||
if error {
|
||||
@ -96,8 +96,8 @@ import UIKit
|
||||
open override var text: String? {
|
||||
get { textField.text }
|
||||
set {
|
||||
textField.text = newValue
|
||||
textEntryFieldModel?.text = newValue
|
||||
textField.text = newValue
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,9 +220,7 @@ import UIKit
|
||||
|
||||
@discardableResult
|
||||
@objc override open func resignFirstResponder() -> Bool {
|
||||
if validateWhenDoneEditing {
|
||||
validateText()
|
||||
}
|
||||
if validateWhenDoneEditing { validateText() }
|
||||
textField.resignFirstResponder()
|
||||
isSelected = false
|
||||
return true
|
||||
@ -237,6 +235,11 @@ import UIKit
|
||||
/// Executes on UITextField.textDidBeginEditingNotification
|
||||
@objc override func startEditing() {
|
||||
super.startEditing()
|
||||
|
||||
if textEntryFieldModel?.clearTextOnTap ?? false {
|
||||
text = ""
|
||||
}
|
||||
|
||||
textField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
@ -255,14 +258,33 @@ import UIKit
|
||||
showError = false
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if let isValid = textEntryFieldModel?.isValid {
|
||||
self.isValid = isValid
|
||||
}
|
||||
|
||||
regexTextFieldOutputIfAvailable()
|
||||
|
||||
shouldShowError(!isValid)
|
||||
}
|
||||
|
||||
func regexTextFieldOutputIfAvailable() {
|
||||
|
||||
if let regex = textEntryFieldModel?.displayFormat,
|
||||
let mask = textEntryFieldModel?.displayMask,
|
||||
let finalText = text {
|
||||
|
||||
let range = NSRange(finalText.startIndex..., in: finalText)
|
||||
|
||||
if let regex = try? NSRegularExpression(pattern: regex) {
|
||||
let maskedText = regex.stringByReplacingMatches(in: finalText,
|
||||
range: range,
|
||||
withTemplate: mask)
|
||||
textField.text = maskedText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func dismissFieldInput(_ sender: Any?) {
|
||||
resignFirstResponder()
|
||||
}
|
||||
@ -315,6 +337,10 @@ import UIKit
|
||||
case .password, .secure:
|
||||
textField.isSecureTextEntry = true
|
||||
|
||||
case .numberSecure:
|
||||
textField.isSecureTextEntry = true
|
||||
textField.keyboardType = .numberPad
|
||||
|
||||
case .number:
|
||||
textField.keyboardType = .numberPad
|
||||
|
||||
@ -324,8 +350,12 @@ import UIKit
|
||||
case .phone:
|
||||
textField.keyboardType = .phonePad
|
||||
|
||||
default:
|
||||
break
|
||||
default: break
|
||||
}
|
||||
|
||||
// Override the preset keyboard set in type.
|
||||
if let keyboardType = model.assignKeyboardType() {
|
||||
textField.keyboardType = keyboardType
|
||||
}
|
||||
|
||||
textField.accessibilityIdentifier = model.accessibilityIdentifier
|
||||
@ -333,9 +363,7 @@ import UIKit
|
||||
observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate
|
||||
setupTextFieldToolbar()
|
||||
|
||||
if isSelected {
|
||||
startEditing()
|
||||
}
|
||||
if isSelected { startEditing() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
case password
|
||||
case secure
|
||||
case number
|
||||
case numberSecure
|
||||
case email
|
||||
case text
|
||||
case phone
|
||||
@ -31,7 +32,63 @@
|
||||
public var enabledTextColor: Color = Color(uiColor: .mvmBlack)
|
||||
public var disabledTextColor: Color = Color(uiColor: .mvmCoolGray3)
|
||||
public var textAlignment: NSTextAlignment = .left
|
||||
public var keyboardOverride: String?
|
||||
public var type: EntryType?
|
||||
public var clearTextOnTap: Bool = false
|
||||
public var displayFormat: String?
|
||||
public var displayMask: String?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Reads the keyboardOverride set by server and returns the keyboard type associated with it.
|
||||
func assignKeyboardType() -> UIKeyboardType? {
|
||||
|
||||
guard let keyboardType = keyboardOverride else { return nil }
|
||||
|
||||
var typeInt = 0
|
||||
|
||||
switch keyboardType {
|
||||
case "asciiCapable":
|
||||
typeInt = 1 // Displays a keyboard which can enter ASCII characters
|
||||
|
||||
case "numbersAndPunctuation":
|
||||
typeInt = 2 // Numbers and assorted punctuation.
|
||||
|
||||
case "URL":
|
||||
typeInt = 3 // A type optimized for URL entry (shows . / .com prominently).
|
||||
|
||||
case "numberPad":
|
||||
typeInt = 4 // A number pad with locale-appropriate digits (0-9, ۰-۹, ०-९, etc.). Suitable for PIN entry.
|
||||
|
||||
case "phonePad":
|
||||
typeInt = 5 // A phone pad (1-9, *, 0, #, with letters under the numbers).
|
||||
|
||||
case "namePhonePad":
|
||||
typeInt = 6 // A type optimized for entering a person's name or phone number.
|
||||
|
||||
case "emailAddress":
|
||||
typeInt = 7 // A type optimized for multiple email address entry (shows space @ . prominently).
|
||||
|
||||
case "decimalPad":
|
||||
typeInt = 8 // A number pad with a decimal point.
|
||||
|
||||
case "twitter":
|
||||
typeInt = 9 // A type optimized for twitter text entry (easy access to @ #)
|
||||
|
||||
case "webSearch":
|
||||
typeInt = 10 // A default keyboard type with URL-oriented addition (shows space . prominently).
|
||||
|
||||
case "asciiCapableNumberPad":
|
||||
typeInt = 11 // A number pad (0-9) that will always be ASCII digits.
|
||||
|
||||
default:
|
||||
typeInt = 0 // Default type for the current input method.
|
||||
}
|
||||
|
||||
return UIKeyboardType(rawValue: typeInt)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
@ -42,7 +99,11 @@
|
||||
case textAlignment
|
||||
case enabledTextColor
|
||||
case disabledTextColor
|
||||
case keyboardOverride
|
||||
case type
|
||||
case clearTextOnTap
|
||||
case displayFormat
|
||||
case displayMask
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -54,8 +115,15 @@
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .placeholder)
|
||||
displayFormat = try typeContainer.decodeIfPresent(String.self, forKey: .displayFormat)
|
||||
keyboardOverride = try typeContainer.decodeIfPresent(String.self, forKey: .keyboardOverride)
|
||||
displayMask = try typeContainer.decodeIfPresent(String.self, forKey: .displayMask)
|
||||
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type)
|
||||
|
||||
if let clearTextOnTap = try typeContainer.decodeIfPresent(Bool.self, forKey: .clearTextOnTap) {
|
||||
self.clearTextOnTap = clearTextOnTap
|
||||
}
|
||||
|
||||
if let enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor) {
|
||||
self.enabledTextColor = enabledTextColor
|
||||
}
|
||||
@ -74,8 +142,12 @@
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(placeholder, forKey: .placeholder)
|
||||
try container.encodeIfPresent(textAlignment, forKey: .textAlignment)
|
||||
try container.encodeIfPresent(type, forKey: .type)
|
||||
try container.encodeIfPresent(displayFormat, forKey: .displayFormat)
|
||||
try container.encodeIfPresent(keyboardOverride, forKey: .keyboardOverride)
|
||||
try container.encodeIfPresent(displayMask, forKey: .displayMask)
|
||||
try container.encode(enabledTextColor, forKey: .enabledTextColor)
|
||||
try container.encode(disabledTextColor, forKey: .disabledTextColor)
|
||||
try container.encodeIfPresent(type, forKey: .type)
|
||||
try container.encode(clearTextOnTap, forKey: .clearTextOnTap)
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,17 +149,17 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
||||
|
||||
container.addSubview(textView)
|
||||
|
||||
|
||||
topConstraint = textView.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three)
|
||||
leadingConstraint = textView.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three)
|
||||
trailingConstraint = container.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: Padding.Three)
|
||||
bottomConstraint = container.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: Padding.Three)
|
||||
|
||||
|
||||
topConstraint?.isActive = true
|
||||
leadingConstraint?.isActive = true
|
||||
trailingConstraint?.isActive = true
|
||||
bottomConstraint?.isActive = true
|
||||
|
||||
|
||||
heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0)
|
||||
accessibilityElements = [titleLabel, textView, feedbackLabel]
|
||||
}
|
||||
@ -203,7 +203,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
/// Executes on UITextView.textDidEndEditingNotification
|
||||
@objc override func endInputing() {
|
||||
super.endInputing()
|
||||
|
||||
|
||||
// Don't show error till user starts typing.
|
||||
guard text?.count ?? 0 != 0 else {
|
||||
showError = false
|
||||
@ -253,6 +253,10 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
case .secure, .password:
|
||||
textView.isSecureTextEntry = true
|
||||
|
||||
case .numberSecure:
|
||||
textView.isSecureTextEntry = true
|
||||
textView.keyboardType = .numberPad
|
||||
|
||||
case .number:
|
||||
textView.keyboardType = .numberPad
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ class TextViewEntryFieldModel: TextEntryFieldModel {
|
||||
public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro
|
||||
public var editable: Bool = true
|
||||
public var showsPlaceholder: Bool = false
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -624,6 +624,9 @@ public typealias ActionBlock = () -> ()
|
||||
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
|
||||
font = font.updateSize(sizeObject.getValueBased(onSize: size))
|
||||
}
|
||||
|
||||
// Provide the label additional size information to help calculate its intrinsic content.
|
||||
preferredMaxLayoutWidth = Styler.maxAvailableLayoutWidth(size: size)
|
||||
}
|
||||
|
||||
@objc public func setFont(_ font: UIFont, scale: Bool) {
|
||||
|
||||
@ -79,6 +79,7 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: DigitEntryField.self, viewModelClass: DigitEntryFieldModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ItemDropdownEntryField.self, viewModelClass: ItemDropdownEntryFieldModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: DateDropdownEntryField.self, viewModelClass: DateDropdownEntryFieldModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MultiItemDropdownEntryField.self, viewModelClass: MultiItemDropdownEntryFieldModel.self)
|
||||
|
||||
// MARK:- Selectors
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
|
||||
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
// Fill for left vertical alignment because bottom constraint was breaking with leading. CXTDT-145456
|
||||
stack = Stack<StackModel>.createStack(with: [(view: eyebrowHeadlineBodyLink, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .fill)), (view: rightLabel, model: StackItemModel(horizontalAlignment:.fill, verticalAlignment: .leading))], axis: .horizontal)
|
||||
stack = Stack<StackModel>.createStack(with: [(view: eyebrowHeadlineBodyLink, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .fill)), (view: rightLabel, model: StackItemModel(horizontalAlignment: .trailing, verticalAlignment: .leading))], axis: .horizontal)
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
||||
rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
||||
rightLabel.numberOfLines = 1
|
||||
addMolecule(stack)
|
||||
stack.restack()
|
||||
}
|
||||
|
||||
@ -21,6 +21,9 @@ import Foundation
|
||||
public var peakingUI: Bool?
|
||||
public var peakingArrowColor: Color?
|
||||
public var analyticsData: JSONValueDictionary?
|
||||
public var fieldValue: String?
|
||||
|
||||
public func formFieldValue() -> AnyHashable? { return fieldValue }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
@ -30,6 +33,7 @@ import Foundation
|
||||
case peakingUI
|
||||
case peakingArrowColor
|
||||
case analyticsData
|
||||
case fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -41,6 +45,7 @@ import Foundation
|
||||
peakingUI = try typeContainer.decodeIfPresent(Bool.self, forKey: .peakingUI)
|
||||
peakingArrowColor = try typeContainer.decodeIfPresent(Color.self, forKey: .peakingArrowColor)
|
||||
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
||||
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
@ -50,5 +55,6 @@ import Foundation
|
||||
try container.encodeIfPresent(peakingUI, forKey: .peakingUI)
|
||||
try container.encodeIfPresent(peakingArrowColor, forKey: .peakingArrowColor)
|
||||
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
||||
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,12 +167,17 @@ open class Carousel: View {
|
||||
|
||||
registerCells(with: carouselModel, delegateObject: delegateObject)
|
||||
prepareMolecules(with: carouselModel)
|
||||
FormValidator.setupValidation(for: carouselModel, delegate: delegateObject?.formHolderDelegate)
|
||||
|
||||
setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject)
|
||||
|
||||
pageIndex = carouselModel.index
|
||||
pagingView?.currentIndex = carouselModel.index
|
||||
collectionView.reloadData()
|
||||
if let selectedIndex = carouselModel.selectedIndex {
|
||||
let adjustedIndex = loop ? selectedIndex + 2 : selectedIndex
|
||||
collectionView.selectItem(at: IndexPath(row: adjustedIndex, section: 0), animated: false, scrollPosition: [])
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -391,8 +396,25 @@ extension Carousel: UICollectionViewDataSource {
|
||||
}
|
||||
|
||||
extension Carousel: UICollectionViewDelegate {
|
||||
public func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||
guard let cell = collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol else { return false }
|
||||
return cell.shouldSelect(at: indexPath, delegateObject: delegateObject, additionalData: nil)
|
||||
}
|
||||
|
||||
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
(collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol)?.didSelectCell(at: indexPath, delegateObject: delegateObject, additionalData: nil)
|
||||
// Set the selection in the model
|
||||
if let model = model as? CarouselModel {
|
||||
// Adjust for looping
|
||||
var adjustedIndex = loop ? indexPath.row - 2 : indexPath.row
|
||||
if adjustedIndex < 0 {
|
||||
adjustedIndex = adjustedIndex + numberOfPages
|
||||
}
|
||||
model.selectedIndex = adjustedIndex
|
||||
}
|
||||
if let cell = collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol {
|
||||
cell.didSelectCell(at: indexPath, delegateObject: delegateObject, additionalData: nil)
|
||||
}
|
||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,6 +436,7 @@ extension Carousel: UIScrollViewDelegate {
|
||||
if !animated {
|
||||
scrollViewDidEndScrollingAnimation(collectionView)
|
||||
}
|
||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||
}
|
||||
|
||||
/// Adjusts the current contentOffset if we are going onto buffer cells while looping to help with the endless scrolling appearance.
|
||||
|
||||
@ -9,7 +9,8 @@
|
||||
import UIKit
|
||||
|
||||
|
||||
@objcMembers public class CarouselModel: MoleculeModelProtocol {
|
||||
@objcMembers public class CarouselModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -33,11 +34,31 @@ import UIKit
|
||||
public var leftPadding: CGFloat?
|
||||
public var rightPadding: CGFloat?
|
||||
public var accessibilityText: String?
|
||||
|
||||
public var baseValue: AnyHashable?
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
|
||||
public var selectable = false
|
||||
public var selectedIndex: Int?
|
||||
|
||||
public init(molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]) {
|
||||
self.molecules = molecules
|
||||
}
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard selectable else {
|
||||
// Use visible item value, else index
|
||||
if let fieldValue = molecules[index].formFieldValue() {
|
||||
return fieldValue
|
||||
}
|
||||
return index
|
||||
}
|
||||
// Use selected item value, else index
|
||||
guard let selectedIndex = selectedIndex else { return nil }
|
||||
guard let fieldValue = molecules[selectedIndex].formFieldValue() else { return selectedIndex }
|
||||
return fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
@ -59,6 +80,10 @@ import UIKit
|
||||
case leftPadding
|
||||
case rightPadding
|
||||
case accessibilityText
|
||||
case groupName
|
||||
case fieldKey
|
||||
case selectable
|
||||
case selectedIndex
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -69,6 +94,8 @@ import UIKit
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
molecules = try typeContainer.decodeModels(codingKey: .molecules)
|
||||
index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0
|
||||
selectable = try typeContainer.decodeIfPresent(Bool.self, forKey: .selectable) ?? false
|
||||
selectedIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing)
|
||||
border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border)
|
||||
@ -86,6 +113,11 @@ import UIKit
|
||||
leftPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .leftPadding)
|
||||
rightPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .rightPadding)
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
baseValue = formFieldValue()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -105,5 +137,10 @@ import UIKit
|
||||
try container.encodeIfPresent(leftPadding, forKey: .leftPadding)
|
||||
try container.encodeIfPresent(rightPadding, forKey: .rightPadding)
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encode(groupName, forKey: .groupName)
|
||||
try container.encode(index, forKey: .index)
|
||||
try container.encode(selectable, forKey: .selectable)
|
||||
try container.encode(selectedIndex, forKey: .selectedIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,11 +11,14 @@ import Foundation
|
||||
|
||||
public protocol CarouselItemModelProtocol: ContainerModelProtocol {
|
||||
var analyticsData: JSONValueDictionary? { get set }
|
||||
func formFieldValue() -> AnyHashable?
|
||||
}
|
||||
|
||||
public extension CarouselItemModelProtocol {
|
||||
|
||||
var analyticsData: JSONValueDictionary? {
|
||||
get { return nil }
|
||||
set { analyticsData = newValue }
|
||||
}
|
||||
func formFieldValue() -> AnyHashable? { return nil }
|
||||
}
|
||||
|
||||
@ -19,6 +19,9 @@ public protocol CollectionTemplateItemProtocol: UICollectionViewCell {
|
||||
|
||||
/// Called when the cell will display.
|
||||
func willDisplay()
|
||||
|
||||
/// Handle the selection of cell
|
||||
func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool
|
||||
}
|
||||
|
||||
// Default implementation does nothing
|
||||
@ -26,4 +29,8 @@ extension CollectionTemplateItemProtocol {
|
||||
public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {}
|
||||
|
||||
public func willDisplay() {}
|
||||
|
||||
public func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,11 +116,15 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo
|
||||
|
||||
// MARK: - Override
|
||||
|
||||
open func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||
guard let action = model?.action else { return }
|
||||
Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
open func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool {
|
||||
if let action = model?.action {
|
||||
Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
open func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {}
|
||||
|
||||
// Column logic, set width.
|
||||
override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
|
||||
let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
|
||||
|
||||
@ -7,10 +7,9 @@
|
||||
//
|
||||
// Form fields are items can be interacted with. They have value, and may need to be validated.
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public protocol FormFieldProtocol: FormItemProtocol {
|
||||
|
||||
/// How the validator identifies the field when validating rules.
|
||||
var fieldKey: String? { get set }
|
||||
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
/// Padding is a multiple based on the number 4.
|
||||
public struct Padding {
|
||||
@ -30,19 +28,19 @@ public struct Padding {
|
||||
public static let VerticalMarginSpacing: CGFloat = 24
|
||||
|
||||
public static var horizontalPaddingForApplicationWidth: CGFloat {
|
||||
return MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalMarginSpacing
|
||||
MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalMarginSpacing
|
||||
}
|
||||
|
||||
public static var verticalPaddingForApplicationWidth: CGFloat {
|
||||
return MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalMarginSpacing
|
||||
MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalMarginSpacing
|
||||
}
|
||||
|
||||
public static func horizontalPaddingForSize(_ size: CGFloat) -> CGFloat {
|
||||
return MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBased(onSize: size) ?? HorizontalMarginSpacing
|
||||
MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBased(onSize: size) ?? HorizontalMarginSpacing
|
||||
}
|
||||
|
||||
public static func verticalPaddingForSize(_ size: CGFloat) -> CGFloat {
|
||||
return MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBased(onSize: size) ?? VerticalMarginSpacing
|
||||
MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBased(onSize: size) ?? VerticalMarginSpacing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,7 +209,14 @@ open class Styler {
|
||||
}
|
||||
|
||||
open class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat {
|
||||
return sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? size
|
||||
sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? size
|
||||
}
|
||||
|
||||
/// Provide additional size information to help calculate its intrinsic height.
|
||||
/// - Returns: The available spacing that can be used for intrinsic content width.
|
||||
open class func maxAvailableLayoutWidth(size: CGFloat) -> CGFloat {
|
||||
// The 2 is the product of both sides of padding.
|
||||
size - (Padding.Component.horizontalPaddingForSize(size) * 2)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user