diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 78207194..2b965e63 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + 01FC09E3235E246D003AC9B3 /* RadioButtonWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC09E2235E246D003AC9B3 /* RadioButtonWithLabel.swift */; }; 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; @@ -212,6 +213,7 @@ 0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; + 01FC09E2235E246D003AC9B3 /* RadioButtonWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonWithLabel.swift; sourceTree = ""; }; 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; @@ -573,6 +575,7 @@ D2A514662213885800345BFB /* StandardHeaderView.swift */, D274CA322236A78900B01B62 /* StandardFooterView.swift */, 01004F2F22721C3800991ECC /* RadioButton.swift */, + 01FC09E2235E246D003AC9B3 /* RadioButtonWithLabel.swift */, 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */, D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, @@ -1059,6 +1062,7 @@ D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */, + 01FC09E3235E246D003AC9B3 /* RadioButtonWithLabel.swift in Sources */, D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m index 33cadc8c..e4f889eb 100644 --- a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m +++ b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m @@ -783,7 +783,7 @@ return self.validationRequired; } -- (NSArray *)requiredFields { +- (NSArray *)requiredGroups { return self.requiredFieldsList; } diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField.m b/MVMCoreUI/Atoms/TextFields/MFTextField.m index 28cd5343..cfef9090 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField.m +++ b/MVMCoreUI/Atoms/TextFields/MFTextField.m @@ -301,20 +301,30 @@ return; } - self.formText = [map string:KeyLabel]; - self.groupName = [map string:@"groupName"]; - self.errMessage = [map string:KeyErrorMessage]; - self.fieldKey = [map string:KeyFieldKey]; - - NSString *string = [map stringForKey:KeyValue]; - if (string.length) { + NSString *string = [map string:KeyLabel]; + if (string.length > 0) { + self.formText = string; + } + string = [map string:KeyValue]; + if (string.length > 0) { self.text = string; } - string = [map stringForKey:KeyDisable]; if ([string isEqual:StringY] || [map boolForKey:KeyDisable]) { [self enable:NO]; } + string = [map string:KeyErrorMessage]; + if (string.length > 0) { + self.errMessage = string; + } + + // key used to send text value to server + string = [map string:KeyFieldKey]; + if (string.length > 0) { + self.fieldKey = string; + } + + self.groupName = [map string:@"groupName"]; string = [map string:KeyType]; if ([string isEqualToString:@"dropDown"]) { diff --git a/MVMCoreUI/FormUIHelpers/FormValidationProtocol.swift b/MVMCoreUI/FormUIHelpers/FormValidationProtocol.swift index 27f3f754..49cfacc9 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidationProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidationProtocol.swift @@ -37,5 +37,5 @@ import Foundation @objc optional func enableField(_ enable: Bool) // Returns the list of field keys required to enable/disable - @objc optional func requiredFields() -> [String]? + @objc optional func requiredGroups() -> [String]? } diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index c3cc77fa..fe23da84 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -49,15 +49,15 @@ import MVMCore public func enableByValidation() { for molecule in enableDisableMolecules { - if let requiredFeilds = molecule.requiredFields?(), requiredFeilds.count > 0 { - enableWithGroupName(requiredFeilds, molecule) + if let requiredFields = molecule.requiredGroups?(), requiredFields.count > 0 { + enableWithGroups(requiredFields, molecule) } else { enableIgnoreGroupName(molecule) } } } - public func enableWithGroupName(_ requiredGroupList: [String], _ enableDisableMolecules: FormValidationEnableDisableProtocol) { + public func enableWithGroups(_ requiredGroupList: [String], _ enableDisableMolecule: FormValidationEnableDisableProtocol) { var groupValidityMap: [String: Bool] = [:] for molecule in fieldMolecules { @@ -70,13 +70,16 @@ import MVMCore for groupName in requiredGroupList { valid = groupValidityMap[groupName] ?? false } - enableDisableMolecules.enableField?(valid) + enableDisableMolecule.enableField?(valid) } public func enableIgnoreGroupName(_ enableDisableMolecules: FormValidationEnableDisableProtocol) { var valid = true for molecule in fieldMolecules { valid = valid && molecule.isValidField() + if (!valid) { + break + } } let enableField = valid && (extraValidationBlock?() ?? true) enableDisableMolecules.enableField?(enableField) diff --git a/MVMCoreUI/Molecules/RadioButton.swift b/MVMCoreUI/Molecules/RadioButton.swift index 53fbaefc..a161272a 100644 --- a/MVMCoreUI/Molecules/RadioButton.swift +++ b/MVMCoreUI/Molecules/RadioButton.swift @@ -8,19 +8,15 @@ import UIKit - @objcMembers open class RadioButton: ViewConstrainingView, FormValidationFormFieldProtocol { public let radioButton = MFRadioButton() var delegateObject: MVMCoreUIDelegateObject? - var dummyButton: MFCustomButton? - let label = Label() - + var fieldKey: String? var formValue: Bool? var isRequired: Bool = false var radioButtonModel: RadioButtonModel? - lazy var radioGroupName: String? = { [unowned self] in @@ -53,49 +49,11 @@ import UIKit isAccessibilityElement = true accessibilityTraits = .none accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") - - radioButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.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 + NSLayoutConstraint.constraintPinSubview(toSuperview: radioButton) - if let rightView = createRightView() { - addSubview(rightView) - rightView.leftAnchor.constraint(equalTo: radioButton.rightAnchor, constant: PaddingHorizontalBetweenRelatedItems).isActive = true - rightView.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor, constant: 0).isActive = true - - var constraint = rightView.topAnchor.constraint(equalTo: topAnchor, constant: PaddingOne) - constraint.priority = .defaultHigh - constraint.isActive = true - - constraint = bottomAnchor.constraint(equalTo: rightView.bottomAnchor, constant: PaddingOne) - constraint.priority = .defaultHigh - constraint.isActive = true - } - addActionHandler() - } - - func createRightView() -> ViewConstrainingView? { - let rightView = ViewConstrainingView(constrainingView: label) - return rightView - } - - func addActionHandler() { - - guard dummyButton == nil else { - return - } - - let dummyButton = MFCustomButton(frame: .zero) - self.dummyButton = dummyButton - dummyButton.translatesAutoresizingMaskIntoConstraints = false - addSubview(dummyButton) - NSLayoutConstraint.constraintPinSubview(toSuperview: dummyButton) - bringSubviewToFront(dummyButton) - - dummyButton.add({ [weak self] (button) in + radioButton.performActionForCheck = { [weak self] in self?.tapAction() - }, for: .touchUpInside) + } } func tapAction() { @@ -105,7 +63,6 @@ import UIKit radioButton.isSelected = !radioButton.isSelected } FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol) - changeAccessibilityLabel() } public func isValidField() -> Bool { @@ -138,28 +95,12 @@ extension RadioButton { } fieldKey = jsonDictionary.optionalStringForKey("fieldKey") - isRequired = jsonDictionary.boolForKey("required") + isRequired = jsonDictionary.boolForKey("required") self.delegateObject = delegateObject let radioButtonModel = RadioButtonModel.setupForRadioButtonGroup(radioButton: self, - formValidator: delegateObject?.formValidationProtocol?.formValidatorModel?()) + formValidator: delegateObject?.formValidationProtocol?.formValidatorModel?()) FormValidator.setupValidation(molecule: radioButtonModel, delegate: delegateObject?.formValidationProtocol) - self.radioButtonModel = radioButtonModel - - label.setWithJSON(jsonDictionary.optionalDictionaryForKey(KeyLabel), - delegateObject: delegateObject, - additionalData: additionalData) - changeAccessibilityLabel() - } -} - -// MARK: Accessibility -extension RadioButton { - func changeAccessibilityLabel() { - let stateString = radioButton.isSelected ? "radio_selected_state" : "radio_not_selected_state" - let localizedStringState = MVMCoreUIUtility.hardcodedString(withKey: stateString) ?? "" - let accebilityString = (label.accessibilityLabel ?? (json?.optionalStringForKey("accessibilityText") ?? "")) - + (MVMCoreUIUtility.hardcodedString(withKey: "radio_desc_state") ?? "") + localizedStringState - accessibilityLabel = accebilityString + self.radioButtonModel = radioButtonModel } } diff --git a/MVMCoreUI/Molecules/RadioButtonWithLabel.swift b/MVMCoreUI/Molecules/RadioButtonWithLabel.swift new file mode 100644 index 00000000..3dc5f6e5 --- /dev/null +++ b/MVMCoreUI/Molecules/RadioButtonWithLabel.swift @@ -0,0 +1,117 @@ +// +// RadioButtonWithLabel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 10/21/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class RadioButtonWithLabel: ViewConstrainingView { + + public let radioButton = RadioButton() + var delegateObject: MVMCoreUIDelegateObject? + var dummyButton: MFCustomButton? + let label = Label() + + // 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 setupView() { + super.setupView() + guard subviews.count == 0 else { + return + } + + translatesAutoresizingMaskIntoConstraints = false + radioButton.translatesAutoresizingMaskIntoConstraints = false + addSubview(radioButton) + + isAccessibilityElement = true + accessibilityTraits = .none + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") + + radioButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.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 + + if let rightView = createRightView() { + addSubview(rightView) + rightView.leftAnchor.constraint(equalTo: radioButton.rightAnchor, constant: PaddingHorizontalBetweenRelatedItems).isActive = true + rightView.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor, constant: 0).isActive = true + + var constraint = rightView.topAnchor.constraint(equalTo: topAnchor, constant: PaddingOne) + constraint.priority = .defaultHigh + constraint.isActive = true + + constraint = bottomAnchor.constraint(equalTo: rightView.bottomAnchor, constant: PaddingOne) + constraint.priority = .defaultHigh + constraint.isActive = true + } + addActionHandler() + } + + func createRightView() -> ViewConstrainingView? { + let rightView = ViewConstrainingView(constrainingView: label) + return rightView + } + + func addActionHandler() { + + guard dummyButton == nil else { + return + } + + let dummyButton = MFCustomButton(frame: .zero) + self.dummyButton = dummyButton + dummyButton.translatesAutoresizingMaskIntoConstraints = false + addSubview(dummyButton) + NSLayoutConstraint.constraintPinSubview(toSuperview: dummyButton) + bringSubviewToFront(dummyButton) + + dummyButton.add({ [weak self] (button) in + self?.tapAction() + }, for: .touchUpInside) + } + + func tapAction() { + radioButton.tapAction() + changeAccessibilityLabel() + } +} + +// MARK: - MVMCoreUIMoleculeViewProtocol +extension RadioButtonWithLabel { + @objc open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + self.delegateObject = delegateObject + radioButton.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + label.setWithJSON(json?.optionalDictionaryForKey(KeyLabel), + delegateObject: delegateObject, + additionalData: additionalData) + changeAccessibilityLabel() + } +} + +// MARK: Accessibility +extension RadioButtonWithLabel { + func changeAccessibilityLabel() { + let stateString = radioButton.radioButton.isSelected ? "radio_selected_state" : "radio_not_selected_state" + let localizedStringState = MVMCoreUIUtility.hardcodedString(withKey: stateString) ?? "" + let accebilityString = (label.accessibilityLabel ?? (json?.optionalStringForKey("accessibilityText") ?? "")) + + (MVMCoreUIUtility.hardcodedString(withKey: "radio_desc_state") ?? "") + localizedStringState + accessibilityLabel = accebilityString + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 27302b20..6c2100f3 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -45,6 +45,7 @@ @"multiProgressBar": MultiProgress.class, @"checkbox": MVMCoreUICheckBox.class, @"radioButton": RadioButton.class, + @"radioButtonLabel": RadioButtonWithLabel.class, @"listItem": MoleculeTableViewCell.class, @"accordionListItem": AccordionMoleculeTableViewCell.class, @"switch": MVMCoreUISwitch.class,