From 382a4c5d3b3db66d6b0822882e02a33968ba579b Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Fri, 26 Apr 2019 16:45:13 -0400 Subject: [PATCH] improvments --- MVMCoreUI.xcodeproj/project.pbxproj | 18 ++- .../Atoms/Views/MFView+FormValidation.swift | 21 +++ MVMCoreUI/Atoms/Views/MFView.h | 3 + MVMCoreUI/FormUIHelpers/FormValidator.swift | 9 +- MVMCoreUI/Molecules/RadioButton.swift | 134 ++++++++---------- MVMCoreUI/Molecules/RadioButtonList.swift | 92 ++++++++++++ .../MVMCoreUIMoleculeMappingObject.m | 1 + 7 files changed, 190 insertions(+), 88 deletions(-) create mode 100644 MVMCoreUI/Atoms/Views/MFView+FormValidation.swift create mode 100644 MVMCoreUI/Molecules/RadioButtonList.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b294f7d1..63ff3d19 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -7,10 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 01004F3022721C3800991ECC /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01004F2F22721C3800991ECC /* RadioButton.swift */; }; + 01004F322273972F00991ECC /* MFView+FormValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01004F312273972F00991ECC /* MFView+FormValidation.swift */; }; 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618A224BBE7700E1557D /* FormValidator.swift */; }; 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */; }; 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */; }; - 01157B94225D376D00F15D92 /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01157B93225D376D00F15D92 /* RadioButton.swift */; }; + 01157B94225D376D00F15D92 /* RadioButtonList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01157B93225D376D00F15D92 /* RadioButtonList.swift */; }; 0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198F79E225679870066C936 /* FormValidationProtocol.swift */; }; 0198F7A62256A80B0066C936 /* MFRadioButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 0198F7A02256A80A0066C936 /* MFRadioButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 0198F7A22256A80A0066C936 /* MFRadioButton.m */; }; @@ -165,10 +167,12 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 01004F2F22721C3800991ECC /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = ""; }; + 01004F312273972F00991ECC /* MFView+FormValidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFView+FormValidation.swift"; sourceTree = ""; }; 0105618A224BBE7700E1557D /* FormValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidator.swift; sourceTree = ""; }; 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; - 01157B93225D376D00F15D92 /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = ""; }; + 01157B93225D376D00F15D92 /* RadioButtonList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonList.swift; sourceTree = ""; }; 0198F79E225679870066C936 /* FormValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidationProtocol.swift; sourceTree = ""; }; 0198F7A02256A80A0066C936 /* MFRadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFRadioButton.h; sourceTree = ""; }; 0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = ""; }; @@ -442,7 +446,8 @@ D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */, D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */, D274CA322236A78900B01B62 /* StandardFooterView.swift */, - 01157B93225D376D00F15D92 /* RadioButton.swift */, + 01157B93225D376D00F15D92 /* RadioButtonList.swift */, + 01004F2F22721C3800991ECC /* RadioButton.swift */, ); path = Molecules; sourceTree = ""; @@ -561,11 +566,10 @@ D29DF17D21E69E26003B2FB9 /* Views */ = { isa = PBXGroup; children = ( - 0198F7A02256A80A0066C936 /* MFRadioButton.h */, - 0198F7A22256A80A0066C936 /* MFRadioButton.m */, DBC4391622442196001AB423 /* CaretView.swift */, DBC4391722442197001AB423 /* DashLine.swift */, D29DF17E21E69E2E003B2FB9 /* MFView.h */, + 01004F312273972F00991ECC /* MFView+FormValidation.swift */, D29DF17F21E69E2E003B2FB9 /* MFView.m */, D29DF31E21ED0CBA003B2FB9 /* LabelView.h */, D29DF31F21ED0CBA003B2FB9 /* LabelView.m */, @@ -871,6 +875,7 @@ D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */, D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */, D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */, + 01004F3022721C3800991ECC /* RadioButton.swift in Sources */, D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */, D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */, D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */, @@ -885,6 +890,7 @@ D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */, 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */, D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */, + 01004F322273972F00991ECC /* MFView+FormValidation.swift in Sources */, D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */, D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, @@ -900,7 +906,7 @@ D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, - 01157B94225D376D00F15D92 /* RadioButton.swift in Sources */, + 01157B94225D376D00F15D92 /* RadioButtonList.swift in Sources */, D29DF18121E69E50003B2FB9 /* MFView.m in Sources */, D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */, D29DF17A21E69E1F003B2FB9 /* MFCustomButton.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/MFView+FormValidation.swift b/MVMCoreUI/Atoms/Views/MFView+FormValidation.swift new file mode 100644 index 00000000..9e4fe2a9 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/MFView+FormValidation.swift @@ -0,0 +1,21 @@ +// +// MFView+FormValidation.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 4/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +extension FormValidationProtocol where Self: MFView { + + func setupFormValidation(delegateObject: DelegateObject?) { + if let delegateObject = delegateObject as? MVMCoreUIDelegateObject, + let formValidationProtocol = delegateObject.formValidationProtocol { + FormValidator.setupValidation(molecule: self, delegate:formValidationProtocol) + formValidator = FormValidator.getFormValidatorFor(delegate:formValidationProtocol) + } + } +} diff --git a/MVMCoreUI/Atoms/Views/MFView.h b/MVMCoreUI/Atoms/Views/MFView.h index 5e32ff0a..079e3c3a 100644 --- a/MVMCoreUI/Atoms/Views/MFView.h +++ b/MVMCoreUI/Atoms/Views/MFView.h @@ -10,8 +10,11 @@ #import @import MVMCore.MVMCoreViewProtocol; +@class FormValidator; + @interface MFView : UIView +@property (nullable, strong, nonatomic) FormValidator *formValidator; @property (nullable, nonatomic, strong) NSDictionary *json; // Called in the initialization functions. Can setup ui here. diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index 1b546d69..5eb28904 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -40,10 +40,7 @@ import UIKit public func enableByValidation() { var valid = true for molecule in molecules { - if let isValidField = molecule.isValidField, - isValidField() == false { - valid = false - } + valid = valid && (molecule.isValidField?() ?? true) } let enableField = valid && (extraValidationBlock?() ?? true) shouldEnable(enableField) @@ -51,9 +48,7 @@ import UIKit public func shouldEnable(_ enable: Bool) { for molecule in molecules { - if let enableField = molecule.enableField { - enableField(enable) - } + molecule.enableField?(enable) } } } diff --git a/MVMCoreUI/Molecules/RadioButton.swift b/MVMCoreUI/Molecules/RadioButton.swift index 7703b7dc..4fb469fd 100644 --- a/MVMCoreUI/Molecules/RadioButton.swift +++ b/MVMCoreUI/Molecules/RadioButton.swift @@ -2,17 +2,19 @@ // RadioButton.swift // MVMCoreUI // -// Created by Suresh, Kamlesh on 4/9/19. +// Created by Suresh, Kamlesh on 4/25/19. // Copyright © 2019 Verizon Wireless. All rights reserved. // import UIKit -@objcMembers open class RadioButton: ViewConstrainingView, FormValidationProtocol{ - var moleculeJson: [AnyHashable: Any]? - var selectedRadioButton: MFRadioButton? - var selectedValue: String? +@objcMembers open class RadioButton: ViewConstrainingView, FormValidationProtocol{ + + var selectedRadioButton: MFRadioButton? + let radioButton = MFRadioButton() + let label = Label() + var target: RadioButtonListProtocol? // MARK: - Inits public init() { @@ -27,84 +29,67 @@ import UIKit super.init(coder: aDecoder) } + public init(target: RadioButtonListProtocol) { + super.init(frame: .zero) + self.target = target + } + + open override func setupView() { + super.setupView() + self.translatesAutoresizingMaskIntoConstraints = false + + radioButton.translatesAutoresizingMaskIntoConstraints = false + addSubview(radioButton) + + addSubview(label) + + radioButton.leftAnchor.constraint(equalTo: leftAnchor, constant: 0).isActive = true + radioButton.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: PaddingOne).isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: radioButton.bottomAnchor, constant: PaddingOne).isActive = true + radioButton.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + label.leftAnchor.constraint(equalTo: radioButton.rightAnchor, constant: PaddingTwo).isActive = true + label.rightAnchor.constraint(equalTo: rightAnchor, constant: 0).isActive = true + label.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: PaddingOne).isActive = true + label.bottomAnchor.constraint(greaterThanOrEqualTo: bottomAnchor, constant: PaddingOne).isActive = true + label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + } + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - self.moleculeJson = json // Configure class properties with JSON values - guard let jsonDictionary = moleculeJson, - let optionsList = jsonDictionary.optionalArrayForKey("optionsList") else { - return + guard let jsonDictionary = json else { + return } - - if let delegateObject = delegateObject as? MVMCoreUIDelegateObject { - FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol) - } - - var items:[UIView] = [] - for option in optionsList { - if let itemUI = createOptionItem(option as? [AnyHashable: Any]) { - items.append(itemUI) - } - } - - let verticalSpace = MFStyler.defaultVerticalPadding(forSize: MVMCoreUIUtility.getWidth()) - StackableViewController.populateView(self, - withUIArray: items) { (item) -> UIEdgeInsets in - return UIEdgeInsets(top: verticalSpace, - left: 0, - bottom: 0, - right: 0) - } - } - - func createOptionItem(_ optionJson: [AnyHashable: Any]?) -> UIView? { - - guard let json = optionJson else { - return nil - } - - let containerView = ViewConstrainingView.empty() - let radioButton = MFRadioButton() - radioButton.translatesAutoresizingMaskIntoConstraints = false - containerView.addSubview(radioButton) - - let label = MFLabel.commonLabel() - label.setWithJSON(json.dictionaryForKey(KeyLabel), delegateObject: nil, additionalData: nil) - containerView.addSubview(label) - - radioButton.leftAnchor.constraint(equalTo: containerView.leftAnchor, constant: 0).isActive = true - radioButton.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: PaddingOne).isActive = true - containerView.bottomAnchor.constraint(greaterThanOrEqualTo: radioButton.bottomAnchor, constant: PaddingOne).isActive = true - radioButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true - label.leftAnchor.constraint(equalTo: radioButton.rightAnchor, constant: PaddingTwo).isActive = true - label.rightAnchor.constraint(equalTo: containerView.rightAnchor, constant: 0).isActive = true - label.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: PaddingOne).isActive = true - label.bottomAnchor.constraint(greaterThanOrEqualTo: containerView.bottomAnchor, constant: PaddingOne).isActive = true - label.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true - - addActionHandler(containerView, radioButton, json) - return containerView + setupFormValidation(delegateObject: delegateObject) + label.setWithJSON(jsonDictionary.dictionaryForKey(KeyLabel), delegateObject: nil, additionalData: nil) + addActionHandler() } - func addActionHandler(_ containerView: UIView, _ radioButton: MFRadioButton, _ optionJson: [AnyHashable: Any]) { + func addActionHandler() { + let dummyButton = MFCustomButton(frame: .zero) dummyButton.translatesAutoresizingMaskIntoConstraints = false - containerView.addSubview(dummyButton) + addSubview(dummyButton) NSLayoutConstraint.constraintPinSubview(toSuperview: dummyButton) - containerView.bringSubviewToFront(dummyButton) + bringSubviewToFront(dummyButton) dummyButton.add({ (button) in - if let selectedbutton = self.selectedRadioButton { - selectedbutton.isSelected = false - } - self.selectedValue = optionJson.optionalStringForKey(KeyValue) - self.selectedRadioButton = radioButton - self.selectedRadioButton?.isSelected = true + self.tapAction() }, for: .touchUpInside) } + func tapAction() { + if let target = target { + target.selected?(self) + } else { + radioButton.isSelected = !radioButton.isSelected + } + formValidator?.enableByValidation() + } + func getColor( _ json: [AnyHashable: Any], _ key: String) -> UIColor? { if let colorHex = json.optionalStringForKey(key) { return UIColor.mfGet(forHex: colorHex) @@ -112,24 +97,23 @@ import UIKit return nil } } - - open override func setupView() { - super.setupView() - self.translatesAutoresizingMaskIntoConstraints = false - } // Used to check the validity of the field, to enable/disable the primary button. @objc public func isValidField() -> Bool { - return selectedValue != nil + if !radioButton.isSelected { + return true + } + return formFieldValue() != nil } // The Field name key value pair for sending to server @objc public func formFieldName() -> String? { - return moleculeJson?.stringForkey("fieldKey") + return radioButton.isSelected ? json?.stringForkey("fieldKey") : nil } // The Feild value key value paid for sending to server @objc public func formFieldValue() -> String? { - return selectedValue + return radioButton.isSelected ? json?.stringForkey(KeyValue) : nil } } + diff --git a/MVMCoreUI/Molecules/RadioButtonList.swift b/MVMCoreUI/Molecules/RadioButtonList.swift new file mode 100644 index 00000000..e0393927 --- /dev/null +++ b/MVMCoreUI/Molecules/RadioButtonList.swift @@ -0,0 +1,92 @@ +// +// RadioButton.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 4/9/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objc public protocol RadioButtonListProtocol: NSObjectProtocol { + + @objc optional func selected(_ radioButton: RadioButton) +} + + +@objcMembers open class RadioButtonList: ViewConstrainingView, FormValidationProtocol, RadioButtonListProtocol { + + var selectedRadioButton: RadioButton? + var selectedValue: String? + + // MARK: - Inits + public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: frame) + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + // Configure class properties with JSON values + guard let jsonDictionary = json, + let optionsList = jsonDictionary.optionalArrayForKey("optionsList") as? [[AnyHashable: Any]], + let delegateObject = delegateObject as? MVMCoreUIDelegateObject else { + return + } + + setupFormValidation(delegateObject: delegateObject) + var items:[UIView] = [] + for option in optionsList { + let radioButton = RadioButton(target: self) + radioButton.setWithJSON(option, delegateObject: delegateObject, additionalData: nil) + items.append(radioButton) + } + + let verticalSpace = MFStyler.defaultVerticalPadding(forSize: MVMCoreUIUtility.getWidth()) + StackableViewController.populateView(self, + withUIArray: items) { (item) -> UIEdgeInsets in + return UIEdgeInsets(top: verticalSpace, + left: 0, + bottom: 0, + right: 0) + } + } + + public func selected(_ radioButton: RadioButton) { + selectedRadioButton?.radioButton.isSelected = false + selectedRadioButton = radioButton + selectedRadioButton?.radioButton.isSelected = true + } + + open override func setupView() { + super.setupView() + self.translatesAutoresizingMaskIntoConstraints = false + } + + // Used to check the validity of the field, to enable/disable the primary button. + @objc public func isValidField() -> Bool { + if !(json?.boolForKey("required") ?? true) { + return true + } + + return selectedRadioButton?.isValidField() ?? false + } + + // The Field name key value pair for sending to server + @objc public func formFieldName() -> String? { + return selectedRadioButton?.formFieldName() + } + + // The Feild value key value paid for sending to server + @objc public func formFieldValue() -> String? { + return selectedRadioButton?.formFieldValue() + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 6f1b577b..759f65c4 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -33,6 +33,7 @@ @"caretView": CaretView.class, @"caretButton": CaretButton.class, @"textField" : MFTextField.class, + @"radioButtonList": RadioButtonList.class, @"radioButton": RadioButton.class } mutableCopy]; });