This commit is contained in:
Suresh, Kamlesh 2019-09-10 10:42:08 -04:00
commit fe066f5530
40 changed files with 939 additions and 155 deletions

View File

@ -11,21 +11,26 @@
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 */; };
016A1071228122180009D605 /* SwitchLineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016A1070228122180009D605 /* SwitchLineItem.swift */; };
0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */; };
01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */; };
01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D902327ECE600EF99AA /* CornerLabels.swift */; };
01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D922327ECFB00EF99AA /* ProgressBar.swift */; };
01509D952327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D942327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.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 */; };
01CA51B5229716F60071A6EE /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CA51B4229716F60071A6EE /* Switch.swift */; };
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, ); }; };
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; };
D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */; };
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479892314445E003FCCF9 /* LabelSwitch.swift */; };
D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */; };
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */; };
D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */; };
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */; };
D22D1F1A220341F60077CEC0 /* MVMCoreUICheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */; settings = {ATTRIBUTES = (Public, ); }; };
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */; };
D22D1F1E220343560077CEC0 /* MVMCoreUICheckMarkView.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -176,7 +181,6 @@
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; };
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; };
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; };
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */; };
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; };
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; };
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */; };
@ -192,20 +196,25 @@
0105618A224BBE7700E1557D /* FormValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidator.swift; sourceTree = "<group>"; };
0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = "<group>"; };
0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = "<group>"; };
016A1070228122180009D605 /* SwitchLineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchLineItem.swift; sourceTree = "<group>"; };
0116A4E4228B19640094F3ED /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = "<group>"; };
01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = "<group>"; };
01509D902327ECE600EF99AA /* CornerLabels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = "<group>"; };
01509D922327ECFB00EF99AA /* ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
01509D942327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButtonSwitch.swift; sourceTree = "<group>"; };
0198F79E225679870066C936 /* FormValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidationProtocol.swift; sourceTree = "<group>"; };
0198F7A02256A80A0066C936 /* MFRadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFRadioButton.h; sourceTree = "<group>"; };
0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = "<group>"; };
01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = "<group>"; };
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = "<group>"; };
D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = "<group>"; };
D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUINavigationController.m; sourceTree = "<group>"; };
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
D22479892314445E003FCCF9 /* LabelSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelSwitch.swift; sourceTree = "<group>"; };
D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodySwitch.swift; sourceTree = "<group>"; };
D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraintExtension.swift; sourceTree = "<group>"; };
D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButton.swift; sourceTree = "<group>"; };
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionMoleculeTableViewCell.swift; sourceTree = "<group>"; };
D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckBox.h; sourceTree = "<group>"; };
D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUICheckBox.m; sourceTree = "<group>"; };
D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckMarkView.h; sourceTree = "<group>"; };
@ -360,7 +369,6 @@
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = "<group>"; };
D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = "<group>"; };
D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = "<group>"; };
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = "<group>"; };
D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTableViewController.swift; sourceTree = "<group>"; };
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.swift; sourceTree = "<group>"; };
DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeftRightLabelView.swift; sourceTree = "<group>"; };
@ -395,6 +403,62 @@
path = FormUIHelpers;
sourceTree = "<group>";
};
D224798823142BF2003FCCF9 /* SwitchMolecules */ = {
isa = PBXGroup;
children = (
01509D942327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift */,
D22479892314445E003FCCF9 /* LabelSwitch.swift */,
D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */,
);
path = SwitchMolecules;
sourceTree = "<group>";
};
D224798D2316A988003FCCF9 /* VerticalCombinationViews */ = {
isa = PBXGroup;
children = (
D2A638FC22CA98280052ED1F /* HeadlineBody.swift */,
D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */,
);
path = VerticalCombinationViews;
sourceTree = "<group>";
};
D224798E2316A995003FCCF9 /* HorizontalCombinationViews */ = {
isa = PBXGroup;
children = (
D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */,
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */,
);
path = HorizontalCombinationViews;
sourceTree = "<group>";
};
D224798F2316A99F003FCCF9 /* LeftRightViews */ = {
isa = PBXGroup;
children = (
01509D902327ECE600EF99AA /* CornerLabels.swift */,
D224798823142BF2003FCCF9 /* SwitchMolecules */,
);
path = LeftRightViews;
sourceTree = "<group>";
};
D22479902316A9CB003FCCF9 /* Organisms */ = {
isa = PBXGroup;
children = (
D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */,
D2A6390022CBB1820052ED1F /* Carousel.swift */,
);
path = Organisms;
sourceTree = "<group>";
};
D22479912316A9EF003FCCF9 /* Items */ = {
isa = PBXGroup;
children = (
01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */,
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */,
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */,
);
path = Items;
sourceTree = "<group>";
};
D22D1F582204D2590077CEC0 /* LegacyControllers */ = {
isa = PBXGroup;
children = (
@ -440,6 +504,7 @@
D29DF11E21E6851E003B2FB9 /* TopAlert */,
D29DF10D21E67A70003B2FB9 /* Atoms */,
D29DF10E21E67A77003B2FB9 /* Molecules */,
D22479902316A9CB003FCCF9 /* Organisms */,
D29DF0DF21E418B2003B2FB9 /* Templates */,
D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */,
D29DF0D021E404D4003B2FB9 /* Info.plist */,
@ -482,34 +547,21 @@
D29DF10E21E67A77003B2FB9 /* Molecules */ = {
isa = PBXGroup;
children = (
D22479912316A9EF003FCCF9 /* Items */,
D224798F2316A99F003FCCF9 /* LeftRightViews */,
D224798E2316A995003FCCF9 /* HorizontalCombinationViews */,
D224798D2316A988003FCCF9 /* VerticalCombinationViews */,
D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */,
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */,
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */,
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */,
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */,
D282AACA2243C61700C46919 /* ButtonView.swift */,
016A1070228122180009D605 /* SwitchLineItem.swift */,
01CA51B4229716F60071A6EE /* Switch.swift */,
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */,
D2A514662213885800345BFB /* StandardHeaderView.swift */,
D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */,
D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */,
D274CA322236A78900B01B62 /* StandardFooterView.swift */,
01004F2F22721C3800991ECC /* RadioButton.swift */,
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */,
B8200E182281DC1A007245F4 /* ProgressBarView.swift */,
0116A4E4228B19640094F3ED /* RadioButtonModel.swift */,
B8200E182281DC1A007245F4 /* CornerLabels.swift */,
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
D2A638FC22CA98280052ED1F /* HeadlineBody.swift */,
D2A6390022CBB1820052ED1F /* Carousel.swift */,
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */,
D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */,
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */,
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */,
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */,
D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */,
);
path = Molecules;
sourceTree = "<group>";
@ -542,6 +594,7 @@
D29DF11321E6805F003B2FB9 /* UIColor+MFConvenience.m */,
D29DF11221E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h */,
D29DF11421E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m */,
D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */,
);
path = Categories;
sourceTree = "<group>";
@ -620,6 +673,7 @@
D29DF17021E69E1F003B2FB9 /* MFCustomButton.m */,
D29DF16C21E69E1F003B2FB9 /* PrimaryButton.h */,
D29DF17121E69E1F003B2FB9 /* PrimaryButton.m */,
D282AACA2243C61700C46919 /* ButtonView.swift */,
D29DF16D21E69E1F003B2FB9 /* MFTextButton.h */,
D29DF17221E69E1F003B2FB9 /* MFTextButton.m */,
);
@ -629,6 +683,10 @@
D29DF17D21E69E26003B2FB9 /* Views */ = {
isa = PBXGroup;
children = (
01509D922327ECFB00EF99AA /* ProgressBar.swift */,
D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */,
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */,
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */,
DBC4391622442196001AB423 /* CaretView.swift */,
DBC4391722442197001AB423 /* DashLine.swift */,
DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */,
@ -946,6 +1004,7 @@
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */,
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */,
01004F3022721C3800991ECC /* RadioButton.swift in Sources */,
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */,
@ -953,6 +1012,7 @@
D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */,
D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */,
DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */,
D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */,
D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */,
D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */,
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
@ -967,20 +1027,21 @@
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */,
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */,
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */,
DBEFFA04225A829700230692 /* Label.swift in Sources */,
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
01509D952327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift in Sources */,
D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */,
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */,
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */,
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
D282AACB2243C61700C46919 /* ButtonView.swift in Sources */,
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */,
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */,
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */,
D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */,
@ -996,12 +1057,12 @@
D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */,
D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */,
D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */,
016A1071228122180009D605 /* SwitchLineItem.swift in Sources */,
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */,
D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */,
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */,
D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */,
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
@ -1019,7 +1080,6 @@
D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */,
D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */,
DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */,
01CA51B5229716F60071A6EE /* Switch.swift in Sources */,
0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */,
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */,
@ -1029,11 +1089,13 @@
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */,
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */,
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */,
01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */,
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */,
D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */,
01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */,
D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -33,6 +33,7 @@
@property (nullable, weak, nonatomic) UIView *view;
@property (nullable, weak, nonatomic) IBOutlet UIView *textFieldContainerView;
@property (nullable, weak, nonatomic) IBOutlet UIView *backgroundView;
@property (nullable, weak, nonatomic) IBOutlet UITextField *textField;
@property (nullable, weak, nonatomic) IBOutlet Label *formLabel;
@property (nullable, weak, nonatomic) IBOutlet UIView *separatorView;//make it public so outsider class can know the posistion of it.

View File

@ -11,6 +11,7 @@
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MFTextField">
<connections>
<outlet property="backgroundView" destination="hLn-P1-X1F" id="Qyf-FT-wfd"/>
<outlet property="dashLine" destination="hw1-Eo-Szn" id="WCs-FF-LCg"/>
<outlet property="dropDownCarrotLabel" destination="XuL-hz-X9C" id="Kv1-Pd-Kra"/>
<outlet property="dropDownCarrotWidth" destination="DJA-00-1ne" id="SHb-1H-EZD"/>

View File

@ -9,14 +9,14 @@
import MVMCore
public typealias ActionBlock = () -> Void
public typealias ActionBlock = () -> ()
@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol {
//------------------------------------------------------
// MARK: - General Properties
// MARK: - Properties
//------------------------------------------------------
public var makeWholeViewClickable = false
/// Set this property if you want updateView to update the font based on this standard and the size passed in.
@ -39,19 +39,39 @@ public typealias ActionBlock = () -> Void
//------------------------------------------------------
public var clauses: [ActionableClause] = [] {
didSet { isUserInteractionEnabled = !clauses.isEmpty }
didSet {
isUserInteractionEnabled = !clauses.isEmpty
if clauses.count > 1 {
clauses.sort { first, second in
guard let firstLocation = first.range?.location,
let secondLocation = second.range?.location
else { return false }
return firstLocation < secondLocation
}
}
}
}
/// Used for tappable links in the text.
public struct ActionableClause {
var range: NSRange?
var actionBlock: ActionBlock?
var accessibilityID: Int = 0
func performAction() {
actionBlock?()
}
}
//------------------------------------------------------
// MARK: - Convenience Setter For objective-C
//------------------------------------------------------
/// Sets the clauses array to empty.
@objc public func setEmptyClauses() {
clauses = []
}
//------------------------------------------------------
// MARK: - Initialization
//------------------------------------------------------
@ -62,6 +82,8 @@ public typealias ActionBlock = () -> Void
numberOfLines = 0
lineBreakMode = .byWordWrapping
translatesAutoresizingMaskIntoConstraints = false
clauses = []
accessibilityCustomActions = []
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:)))
tapGesture.numberOfTapsRequired = 1
@ -113,6 +135,7 @@ public typealias ActionBlock = () -> Void
return label
}
/// H32 -> Head
@objc public static func commonLabelH32(_ scale: Bool) -> Label {
let label = Label.label()
label.styleH32(scale)
@ -140,18 +163,20 @@ public typealias ActionBlock = () -> Void
return label
}
/// B20 -> Body
@objc public static func commonLabelB20(_ scale: Bool) -> Label {
let label = Label.label()
label.styleB20(scale)
return label
}
/// Default
@objc open class func label() -> Label {
return Label(frame: .zero)
}
//------------------------------------------------------
// MARK: - Functions
// MARK: - Style
//------------------------------------------------------
@objc public static func setLabel(_ label: UILabel?, withHTML html: String?) {
@ -189,6 +214,10 @@ public typealias ActionBlock = () -> Void
}
}
if let wholeViewIsClickable = json?.boolForKey("makeWholeViewClickable") {
(label as? Label)?.makeWholeViewClickable = wholeViewIsClickable
}
if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty {
label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
}
@ -229,11 +258,28 @@ public typealias ActionBlock = () -> Void
case "strikethrough":
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
attributedString.addAttribute(.baselineOffset, value: 0, range: range)
case "color":
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
attributedString.removeAttribute(.foregroundColor, range: range)
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
}
case "image":
let fontSize = attribute["size"] as? CGFloat ?? label.font.pointSize
let imageName = attribute["name"] as? String ?? "externalLink"
let imageURL = attribute["URL"] as? String
let imageAttachment: NSTextAttachment
if let url = imageURL, let label = label as? Label {
imageAttachment = Label.getTextAttachmentFrom(url: url, dimension: fontSize, label: label)
} else {
imageAttachment = Label.getTextAttachmentImage(name: imageName, dimension: fontSize)
}
let mutableString = NSMutableAttributedString()
mutableString.append(NSAttributedString(attachment: imageAttachment))
attributedString.insert(mutableString, at: location)
case "font":
if let fontStyle = attribute.optionalStringForKey("style") {
let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle)
@ -243,13 +289,13 @@ public typealias ActionBlock = () -> Void
} else {
let fontSize = attribute["size"] as? CGFloat
var font: UIFont?
if let fontName = attribute.optionalStringForKey("name") {
font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize)
} else if let fontSize = fontSize {
font = label.font.withSize(fontSize)
}
if let font = font {
attributedString.removeAttribute(.font, range: range)
attributedString.addAttribute(.font, value: font, range: range)
@ -259,10 +305,9 @@ public typealias ActionBlock = () -> Void
guard let actionLabel = label as? Label else { continue }
actionLabel.addActionAttributes(range: range, string: attributedString)
actionLabel.clauses.append(ActionableClause(range: range,
actionBlock: actionLabel.createActionBlockFrom(actionMap: json,
additionalData: additionalData,
delegateObject: delegate)))
let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate)
actionLabel.appendActionableClause(range: range, actionBlock: actionBlock)
default:
continue
}
@ -271,8 +316,6 @@ public typealias ActionBlock = () -> Void
}
}
//------------------------------------------------------
// MARK: - Methods
//------------------------------------------------------
@ -323,15 +366,28 @@ public typealias ActionBlock = () -> Void
if let originalAttributedString = originalAttributedString {
let attributedString = NSMutableAttributedString(attributedString: originalAttributedString)
attributedString.removeAttribute(.font, range: NSRange(location: 0, length: attributedString.length))
originalAttributedString.enumerateAttribute(.font, in: NSRange(location: 0, length: originalAttributedString.length), options: [], using: { value, range, stop in
// Loop the original attributed string, resize the fonts.
// Loop the original attributed string, resize the fonts.
originalAttributedString.enumerateAttribute(.font, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in
if let fontObj = value as? UIFont, let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: fontObj.pointSize)?.getValueBased(onSize: size) {
attributedString.addAttribute(.font, value: fontObj.withSize(stylerSize) as Any, range: range)
}
})
}
// Loop the original attributed string, resize the image attachments.
originalAttributedString.enumerateAttribute(.attachment, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in
if let attachment = value as? NSTextAttachment,
let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: attachment.bounds.width)?.getValueBased(onSize: size) {
let dimension = round(stylerSize)
attachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension)
}
}
attributedText = attributedString
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject: MFSizeObject = self.sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
self.font = self.font.withSize(sizeObject.getValueBased(onSize: size))
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
font = font.withSize(sizeObject.getValueBased(onSize: size))
}
}
@ -353,23 +409,98 @@ public typealias ActionBlock = () -> Void
}
}
/**
Appends an external link image to the end of the attributed string.
Will provide one whitespace to the left of the icon; adds 2 chars to the end of the string.
*/
@objc public func appendExternalLinkIcon() {
guard let attributedText = attributedText else { return }
let mutableString = NSMutableAttributedString(attributedString: attributedText)
mutableString.append(NSAttributedString(string: " "))
mutableString.append(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)))
self.attributedText = mutableString
}
///Appends an external link image to the end of the attributed string.
public func addExternalLinkIcon() {
/**
Insert external link icon anywhere within text of Label.
- Note: Each icon insertion adds 1 additional characters to the overall text length.
Therefore, you **MUST** insert icons and links in the order they would appear.
- parameter index: Location within the associated text to insert an external Link Icon
*/
public func insertExternalLinkIcon(at index: Int) {
let size = round(font.pointSize * 0.8)
guard let attributedText = attributedText, index <= attributedText.string.count && index >= 0 else { return }
guard let attributedText = self.attributedText else { return }
let mutableString = NSMutableAttributedString(attributedString: attributedText)
mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index)
let fullString = NSMutableAttributedString(attributedString: attributedText)
self.attributedText = mutableString
}
/*
Retrieves an NSTextAttachment for NSAttributedString that is prepped to be inserted with the text.
- parameter name: The Asset name of the image. DEFAULT: "externalLink"
- parameter dimension: length of the height and width of the image. Will be 80% the passed magnitude.
*/
static func getTextAttachmentImage(name: String = "externalLink", dimension: CGFloat) -> NSTextAttachment {
let dimension = round(dimension * 0.8)
let imageAttachment = NSTextAttachment()
imageAttachment.image = MVMCoreUIUtility.imageNamed("externalLink")
imageAttachment.bounds = CGRect(x: 0, y: 0, width: size, height: size)
imageAttachment.image = MVMCoreUIUtility.imageNamed(name)
imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension)
fullString.append(NSAttributedString(string: " "))
fullString.append(NSAttributedString(attachment: imageAttachment))
self.attributedText = fullString
return imageAttachment
}
static func getTextAttachmentFrom(url: String, dimension: CGFloat, label: Label) -> NSTextAttachment {
let dimension = round(dimension * 0.8)
let imageAttachment = NSTextAttachment()
imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension)
DispatchQueue.global(qos: .default).async {
guard let url = URL(string: url),
let data = try? Data(contentsOf: url)
else { return }
DispatchQueue.main.sync {
imageAttachment.image = UIImage(data: data)
label.setNeedsDisplay()
}
}
return imageAttachment
}
/// Call to detect in the attributedText contains an NSTextAttachment.
func textContainsTextAttachment() -> Bool {
guard let attributedText = attributedText else { return false }
var containsAttachment = false
attributedText.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText.length), options: []) { value, range, stop in
if value is NSTextAttachment {
containsAttachment = true
return
}
}
return containsAttachment
}
func appendActionableClause(range: NSRange, actionBlock: @escaping ActionBlock) {
let accessibleAction = customAccessibilityAction(range: range)
clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1))
}
}
@ -382,6 +513,8 @@ extension Label {
textAlignment = .left
originalAttributedString = nil
styleB2(true)
accessibilityCustomActions = []
clauses = []
}
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
@ -410,7 +543,7 @@ extension Label {
// MARK: - Multi-Action Functionality
extension Label {
/// Reseting to default Label values.
/// Applied to existing text. Removes underlines of tappable links and assoated actionable clauses.
@objc public func clearActionableClauses() {
guard let attributedText = attributedText else { return }
@ -422,6 +555,7 @@ extension Label {
}
self.attributedText = mutableAttributedString
accessibilityElements = []
clauses = []
}
@ -452,38 +586,36 @@ extension Label {
Provides an actionable range of text.
- Attention: This method expects text to be set first. Otherwise, it will do nothing.
- Parameters:
- range: The range of text to be tapped.
- actionBlock: The code triggered when tapping the range of text.
- parameter range: The range of text to be tapped.
- parameter actionBlock: The code triggered when tapping the range of text.
*/
@objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) {
setActionAttributes(range: range)
clauses.append(ActionableClause(range: range, actionBlock: actionBlock))
appendActionableClause(range: range, actionBlock: actionBlock)
}
/**
Provides an actionable range of text.
- Attention: This method expects text to be set first. Otherwise, it will do nothing.
- Parameters:
- range: The range of text to be tapped.
- actionMap:
- delegate:
- additionalData:
- parameter range: The range of text to be tapped.
- parameter actionMap:
- parameter delegate:
- parameter additionalData:
*/
@objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
setActionAttributes(range: range)
clauses.append(ActionableClause(range: range,
actionBlock: createActionBlockFrom(actionMap: actionMap,
additionalData: additionalData,
delegateObject: delegateObject)))
let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
appendActionableClause(range: range, actionBlock: actionBlock)
}
@objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) {
for clause in clauses {
// This determines if we tapped on the desired range of text.
if let range = clause.range, gesture.didTapAttributedTextInLabel(self, inRange: range) {
clause.performAction()
return
@ -497,15 +629,23 @@ extension UITapGestureRecognizer {
func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange) -> Bool {
// There would only ever be one clause to act on.
if label.makeWholeViewClickable {
return true
}
// Must configure the attributed string to translate what would appear on screen to accurately analyze.
guard let attributedText = label.attributedText else { return false }
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = label.textAlignment
let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText)
stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count))
let textStorage = NSTextStorage(attributedString: stagedAttributedString)
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: .zero)
let textStorage = NSTextStorage(attributedString: attributedText)
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
@ -515,8 +655,37 @@ extension UITapGestureRecognizer {
textContainer.maximumNumberOfLines = label.numberOfLines
textContainer.size = label.bounds.size
let indexOfCharacter = layoutManager.characterIndex(for: location(in: label), in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
return NSLocationInRange(indexOfCharacter, targetRange)
let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer)
return NSLocationInRange(indexOfGlyph, targetRange)
}
}
// MARK: - Accessibility
extension Label {
func customAccessibilityAction(range: NSRange) -> UIAccessibilityCustomAction? {
guard let text = text else { return nil }
if accessibilityHint == nil {
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint")
}
let actionText = NSString(string: text).substring(with: range)
let accessibleAction = UIAccessibilityCustomAction(name: actionText, target: self, selector: #selector(accessibilityCustomAction(_:)))
accessibilityCustomActions?.append(accessibleAction)
return accessibleAction
}
@objc public func accessibilityCustomAction(_ action: UIAccessibilityCustomAction) {
for clause in clauses {
if action.hash == clause.accessibilityID {
clause.performAction()
return
}
}
}
}

View File

@ -64,7 +64,15 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
if newActionBlock == nil {
label?.clearActionableClauses()
} else {
label?.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock)]
guard let label = label else { return }
let accessibleAction = UIAccessibilityCustomAction(name: actionText ?? "", target: label, selector: #selector(label.accessibilityCustomAction(_:)))
label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, accessibilityID: accessibleAction.hash)]
label.accessibilityCustomActions = [accessibleAction]
if label.accessibilityHint == nil {
label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint")
}
}
}
}

View File

@ -8,10 +8,11 @@
#import <UIKit/UIKit.h>
#import <MVMCoreUI/MVMCoreUIMoleculeViewProtocol.h>
@import MVMCore.MVMCoreViewProtocol;
typedef void(^ValueChangeBlock)(void);
@interface MVMCoreUISwitch : UIControl <MVMCoreViewProtocol>
@interface MVMCoreUISwitch : UIControl <MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol>
@property (assign, nonatomic, getter=isOn) BOOL on;
@property (nullable, strong, nonatomic) UIColor *onTintColor;
@ -23,8 +24,8 @@ typedef void(^ValueChangeBlock)(void);
@property (nonatomic) BOOL shouldTouchToSwitch;
@property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock;
+ (nullable instancetype)mvmSwitchDefault;
+ (nullable instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block;
+ (nonnull instancetype)mvmSwitchDefault;
+ (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block;
- (void)setState:(BOOL)state animated:(BOOL)animated;

View File

@ -14,6 +14,7 @@
#import <MVMCoreUI/UIColor+MFConvenience.h>
#import <MVMCoreUI/MVMCoreUICommonViewsUtility.h>
#import <MVMCoreUI/MVMCoreUIUtility.h>
#import <MVMCoreUI/MVMCoreUI-Swift.h>
const CGFloat SwitchWidth = 42;
const CGFloat SwitchHeight = 22;
@ -21,7 +22,7 @@ const CGFloat SwitchKnobWidth = 20;
const CGFloat SwitchKnobHeight = 20;
const CGFloat SwitchShakeIntensity = 2;
@interface MVMCoreUISwitch ()
@interface MVMCoreUISwitch () <FormValidationProtocol, MVMCoreUIViewConstrainingProtocol>
@property (weak, nonatomic) UIView *baseView;
@property (weak, nonatomic) UIView *knobView;
@ -37,6 +38,9 @@ const CGFloat SwitchShakeIntensity = 2;
@property (nonatomic) BOOL canChangeValue;
@property (strong, nonatomic, nullable) NSDictionary *json;
@property (nullable, strong, nonatomic) DelegateObject *delegate;
@end
@implementation MVMCoreUISwitch
@ -86,7 +90,7 @@ const CGFloat SwitchShakeIntensity = 2;
return mySwitch;
}
+ (nullable instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block {
+ (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block {
MVMCoreUISwitch *mySwitch = [[self alloc] initWithFrame:CGRectZero];
mySwitch.valueChangedBlock = block;
return mySwitch;
@ -137,6 +141,50 @@ const CGFloat SwitchShakeIntensity = 2;
}
}
#pragma mark - MVMCoreUIMoleculeViewProtocol
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
self.json = json;
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
NSString *color = [json string:@"onTintColor"];
if (color) {
self.onTintColor = [UIColor mfGetColorForHex:color];
}
color = [json string:@"offTintColor"];
if (color) {
self.offTintColor = [UIColor mfGetColorForHex:color];
}
color = [json string:@"onKnobTintColor"];
if (color) {
self.onKnobTintColor = [UIColor mfGetColorForHex:color];
}
color = [json string:@"offKnobTintColor"];
if (color) {
self.offKnobTintColor = [UIColor mfGetColorForHex:color];
}
[self setState:[json boolForKey:@"state"] animated:false];
}
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
return [self getSwitchHeight];
}
#pragma mark - MVMCoreUIMoleculeViewProtocol
- (BOOL)needsToBeConstrained {
return YES;
}
- (UIStackViewAlignment)alignment {
return UIStackViewAlignmentTrailing;
}
#pragma mark - UIResponder overide
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
@ -280,6 +328,11 @@ const CGFloat SwitchShakeIntensity = 2;
if (self.valueChangedBlock) {
self.valueChangedBlock();
}
if (self.delegate && [self.delegate respondsToSelector:@selector(formValidationProtocol)] && [[self.delegate performSelector:@selector(formValidationProtocol)] respondsToSelector:@selector(formValidatorModel)]) {
FormValidator *formValidator = [[self.delegate performSelector:@selector(formValidationProtocol)] performSelector:@selector(formValidatorModel)];
[formValidator enableByValidation];
}
}
- (void)setState:(BOOL)state withoutBlockAnimated:(BOOL)animated {
@ -308,7 +361,7 @@ const CGFloat SwitchShakeIntensity = 2;
}
- (BOOL)changeValue{
- (BOOL)changeValue {
self.on^=YES;
self.shouldTouchToSwitch = NO;
[self setState:self.on animated:YES];
@ -349,7 +402,8 @@ const CGFloat SwitchShakeIntensity = 2;
}
#pragma mark - Accessibility
- (BOOL)isAccessibilityElement{
- (BOOL)isAccessibilityElement {
return YES;
}
@ -361,4 +415,18 @@ const CGFloat SwitchShakeIntensity = 2;
return [MVMCoreUIUtility hardcodedStringWithKey:@"AccToggleHint"];
}
#pragma mark FormValidationProtocol
- (BOOL)isValidField {
return self.isOn && [self.json boolForKey:@"required"];
}
- (NSString *)formFieldName {
return [self.json string:KeyFieldKey];
}
- (id)formFieldValue {
return @(self.isOn);
}
@end

View File

@ -41,4 +41,7 @@ typedef enum : NSUInteger {
- (void)setAsLight;
- (void)setAsMedium;
/// Returns if the separator should be visible based on the type.
- (BOOL)shouldBeVisible;
@end

View File

@ -162,6 +162,10 @@
[self setNeedsLayout];
[self layoutIfNeeded];
}
- (BOOL)shouldBeVisible {
return ![[self.json string:KeyType] isEqualToString:@"none"];
}
#pragma mark - Molecule

View File

@ -0,0 +1,44 @@
//
// NSLayoutConstraintExtension.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/28/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import Foundation
public extension NSLayoutConstraint {
static func pinSubviewsCenter(leftView: UIView, rightView: UIView) {
guard let superView = leftView.superview else {
return
}
leftView.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true
leftView.leftAnchor.constraint(equalTo: superView.layoutMarginsGuide.leftAnchor).isActive = true
leftView.topAnchor.constraint(greaterThanOrEqualTo: superView.layoutMarginsGuide.topAnchor).isActive = true
superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: leftView.bottomAnchor).isActive = true
var constraint = leftView.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor)
constraint.priority = .defaultLow
constraint.isActive = true
constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: leftView.bottomAnchor)
constraint.priority = .defaultLow
constraint.isActive = true
rightView.leftAnchor.constraint(greaterThanOrEqualTo: leftView.rightAnchor, constant: 16).isActive = true
rightView.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true
superView.layoutMarginsGuide.rightAnchor.constraint(equalTo: rightView.rightAnchor).isActive = true
rightView.topAnchor.constraint(greaterThanOrEqualTo: superView.layoutMarginsGuide.topAnchor).isActive = true
superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: rightView.bottomAnchor).isActive = true
constraint = rightView.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor)
constraint.priority = .defaultLow
constraint.isActive = true
constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: rightView.bottomAnchor)
constraint.priority = .defaultLow
constraint.isActive = true
}
}

View File

@ -14,8 +14,7 @@ import UIKit
// MARK: - Outlets
//------------------------------------------------------
let title = Label.commonLabelH3(true)
let message = Label.commonLabelB3(true)
let header = HeadlineBody(frame: .zero)
let button = PrimaryButton.primaryTinyButton(false)!
let imageLoader = MFLoadImageView(pinnedEdges: .all)
let leftContainer = ViewConstrainingView.empty()
@ -24,7 +23,7 @@ import UIKit
// MARK: - Properties
//------------------------------------------------------
var bottomTitlePadding: CGFloat = PaddingOne
var buttonHeaderPadding: CGFloat = PaddingTwo
//------------------------------------------------------
// MARK: - Constraints
@ -32,7 +31,6 @@ import UIKit
var imageLeadingConstraint: NSLayoutConstraint?
var buttonTopConstraint: NSLayoutConstraint?
var messageTopConstraint: NSLayoutConstraint?
//------------------------------------------------------
// MARK: - Initialization
@ -68,8 +66,7 @@ import UIKit
addSubview(leftContainer)
addSubview(imageLoader)
leftContainer.addSubview(title)
leftContainer.addSubview(message)
leftContainer.addSubview(header)
leftContainer.addSubview(button)
leftContainer.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
@ -80,17 +77,11 @@ import UIKit
leftContainerBottom.priority = UILayoutPriority(249)
leftContainerBottom.isActive = true
title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true
title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true
leftContainer.trailingAnchor.constraint(equalTo: title.trailingAnchor).isActive = true
messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne)
messageTopConstraint?.isActive = true
message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true
leftContainer.trailingAnchor.constraint(equalTo: message.trailingAnchor).isActive = true
buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo)
header.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true
header.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true
leftContainer.trailingAnchor.constraint(equalTo: header.trailingAnchor).isActive = true
buttonTopConstraint = button.topAnchor.constraint(equalTo: header.bottomAnchor, constant: buttonHeaderPadding)
buttonTopConstraint?.isActive = true
button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true
@ -112,15 +103,12 @@ import UIKit
override open func updateView(_ size: CGFloat) {
super.updateView(size)
title.updateView(size)
message.updateView(size)
header.updateView(size)
button.updateView(size)
imageLoader.updateView(size)
leftContainer.updateView(size)
messageTopConstraint?.constant = title.hasText && message.hasText ? bottomTitlePadding : 0
buttonTopConstraint?.constant = message.hasText || title.hasText ? PaddingTwo : 0
buttonTopConstraint?.constant = header.hasText() ? buttonHeaderPadding : 0
}
public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
@ -133,35 +121,31 @@ import UIKit
private func setDefaultState() {
title.font = MFStyler.fontH3()
message.font = MFStyler.fontB3()
header.headlineLabel.font = MFStyler.fontH3()
header.messageLabel.font = MFStyler.fontB3()
button.setAsSecondaryCustom()
button.isHidden = false
imageLoader.imageView.contentMode = .scaleAspectFit
imageLoader.addSizeConstraintsForAspectRatio = true
bottomTitlePadding = PaddingOne
buttonHeaderPadding = PaddingTwo
}
override open func reset() {
super.reset()
title.reset()
message.reset()
header.reset()
button.reset()
imageLeadingConstraint?.constant = 16
imageLoader.reset()
setDefaultState()
}
open override func setAsMolecule() {
super.setAsMolecule()
title.setAsMolecule()
message.setAsMolecule()
header.setAsMolecule()
button.setAsMolecule()
imageLoader.setAsMolecule()
setDefaultState()
}
@ -170,13 +154,13 @@ import UIKit
guard let dictionary = json else { return }
if let padding = dictionary.optionalCGFloatForKey("bottomTitlePadding") {
bottomTitlePadding = padding
if let padding = dictionary.optionalCGFloatForKey("buttonHeaderPadding") {
buttonHeaderPadding = padding
}
title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData)
message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData)
header.setWithJSON(dictionary.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData)
imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData)
if let buttonDictionary = dictionary.optionalDictionaryForKey("button") {
button.setWithJSON(buttonDictionary, delegateObject: delegateObject, additionalData: additionalData)
} else {

View File

@ -8,12 +8,13 @@
import UIKit
@objcMembers open class TwoButtonView: ButtonView {
open var secondaryButton: PrimaryButton?
@objcMembers open class TwoButtonView: ViewConstrainingView {
open var primaryButton: PrimaryButton? = PrimaryButton.button()
open var secondaryButton: PrimaryButton? = PrimaryButton.button()
open var viewForButtons: UIView?
public var heightConstraint: NSLayoutConstraint?
public override init() {
public init() {
super.init(frame: .zero)
}
@ -34,28 +35,32 @@ import UIKit
open override func updateView(_ size: CGFloat) {
super.updateView(size)
MVMCoreDispatchUtility.performBlock(onMainThread: {
self.primaryButton?.updateView(size)
self.secondaryButton?.updateView(size)
})
}
open override func setupView() {
super.setupView()
setupWithTwoButtons()
secondaryButton?.bordered = true
}
// MARK: - MVMCoreUIMoleculeViewProtocol
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
let primaryButtonMap = json?.optionalDictionaryForKey("primaryButton")
let secondaryButtonMap = json?.optionalDictionaryForKey("secondaryButton")
set(primaryButtonJSON: primaryButtonMap, secondaryButtonJSON: secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData)
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
open override func reset() {
super.reset()
primaryButton?.setAsStandardCustom()
secondaryButton?.setAsSecondaryCustom()
}
// MARK: - Constraining
override func setupButton() {
setupWithTwoButtons()
}
func createPrimaryButton() {
if primaryButton == nil {
primaryButton = PrimaryButton.button()

View File

@ -0,0 +1,46 @@
//
// AccordionMoleculeTableViewCell.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/30/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class AccordionMoleculeTableViewCell: MoleculeTableViewCell {
let accordionButton = createAccordionButton()
static func createAccordionButton() -> MFCustomButton {
let accordionButton = MFCustomButton(type: .custom)
accordionButton.setTitle("+", for: .normal)
accordionButton.setTitleColor(.black, for: .normal)
accordionButton.titleLabel?.font = UIFont.systemFont(ofSize: 40, weight: .ultraLight)
accordionButton.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
return accordionButton
}
override public func setupView() {
customAccessoryView = true
super.setupView()
accessoryView = accordionButton
}
public override func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
accordionButton.isSelected = !accordionButton.isSelected
accordionButton.setTitle(accordionButton.isSelected ? "-" : "+", for: .normal)
guard let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else {
return
}
if accordionButton.isSelected {
delegateObject?.moleculeDelegate?.addMolecules?(molecules, senderIndexPath: indexPath)
} else {
delegateObject?.moleculeDelegate?.removeMolecules?(molecules, senderIndexPath: indexPath)
}
if (json?.boolForKey("hideSeparatorWhenExpanded") ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) {
bottomSeparatorView?.isHidden = accordionButton.isSelected
}
}
}

View File

@ -15,7 +15,6 @@ import UIKit
// In updateView, will set padding to default.
open var updateViewHorizontalDefaults = true
open var updateViewVerticalDefaults = true
// For the accessory view convenience.
public var caretView: CaretView?
@ -32,6 +31,48 @@ import UIKit
case Between = "between"
}
/// For subclasses that want to use a custom accessory view.
open var customAccessoryView = false
public var topMarginPadding: CGFloat = 24
public var bottomMarginPadding: CGFloat = 24
// MARK: - Styling
func style(with styleString: String?) {
guard let styleString = styleString else {
return
}
switch styleString {
case "standard":
styleStandard()
case "header":
styleHeader()
case "none":
styleNone()
default: break
}
}
func styleStandard() {
topMarginPadding = 24
bottomMarginPadding = 24
bottomSeparatorView?.show()
bottomSeparatorView?.setAsLight()
}
func styleHeader() {
topMarginPadding = 48
bottomMarginPadding = 16
bottomSeparatorView?.show()
bottomSeparatorView?.setAsRegular()
}
func styleNone() {
topMarginPadding = 0
bottomMarginPadding = 0
bottomSeparatorView?.hide()
}
// MARK: - Inits
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
@ -45,7 +86,7 @@ import UIKit
// MARK: - MFViewProtocol
public func updateView(_ size: CGFloat) {
MFStyler.setDefaultMarginsFor(self, size: size, horizontal: updateViewHorizontalDefaults, vertical: updateViewVerticalDefaults)
MFStyler.setMarginsFor(self, size: size, defaultHorizontal: updateViewHorizontalDefaults, top: topMarginPadding, bottom: bottomMarginPadding)
if #available(iOS 11.0, *) {
if accessoryView != nil {
// Smaller left margin if accessory view.
@ -91,11 +132,14 @@ import UIKit
public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
self.json = json;
style(with: json?.optionalStringForKey("style"))
if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") {
updateViewHorizontalDefaults = useHorizontalMargins
}
if let useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") {
updateViewVerticalDefaults = useVerticalMargins
if json?.optionalBoolForKey("useVerticalMargins") ?? false {
topMarginPadding = 0
bottomMarginPadding = 0
}
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
@ -103,10 +147,12 @@ import UIKit
}
// Add the caret if there is an action and it's not declared hidden.
if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") {
addCaretViewAccessory()
} else {
accessoryView = nil
if !customAccessoryView {
if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") {
addCaretViewAccessory()
} else {
accessoryView = nil
}
}
// override the separator
@ -138,8 +184,8 @@ import UIKit
public func reset() {
molecule?.reset?()
updateViewVerticalDefaults = true
updateViewHorizontalDefaults = true
styleStandard()
backgroundColor = .white
}
@ -152,9 +198,10 @@ import UIKit
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
return nil
return "\(self)<>"
}
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName)
let moleculeName = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) ?? ""
return "\(self)<\(moleculeName)>"
}
public static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {

View File

@ -0,0 +1,57 @@
//
// HeadlineBodySwitch.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/26/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class HeadlineBodySwitch: ViewConstrainingView {
let headlineBody = HeadlineBody(frame: .zero)
let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault()
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
mvmSwitch.updateView(size)
}
public override func setupView() {
super.setupView()
guard mvmSwitch.superview == nil else {
return
}
headlineBody.styleListItem()
addSubview(headlineBody)
addSubview(mvmSwitch)
NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBody, rightView: mvmSwitch)
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData)
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 30
}
public override func setAsMolecule() {
super.setAsMolecule()
headlineBody.setAsMolecule()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?()
headlineBody.styleListItem()
}
public override func reset() {
super.reset()
headlineBody.reset()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?()
headlineBody.styleListItem()
}
}

View File

@ -0,0 +1,59 @@
//
// SwitchLineItem.swift
// MVMCoreUI
//
// Created by Priya on 5/6/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class HeadlineBodyTextButtonSwitch: ViewConstrainingView {
let headlineBodyTextButton = HeadlineBodyTextButton(frame: .zero)
let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault()
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBodyTextButton.updateView(size)
mvmSwitch.updateView(size)
}
public override func setupView() {
super.setupView()
guard mvmSwitch.superview == nil else {
return
}
headlineBodyTextButton.headlineBody.styleListItem()
addSubview(headlineBodyTextButton)
addSubview(mvmSwitch)
NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBodyTextButton, rightView: mvmSwitch)
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
headlineBodyTextButton.setWithJSON(json?.optionalDictionaryForKey("headlineBodyTextButton"), delegateObject: delegateObject, additionalData: additionalData)
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return HeadlineBodyTextButton.estimatedHeight(forRow: json, delegateObject: delegateObject)
}
public override func setAsMolecule() {
super.setAsMolecule()
headlineBodyTextButton.setAsMolecule()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?()
headlineBodyTextButton.headlineBody.styleListItem()
}
public override func reset() {
super.reset()
headlineBodyTextButton.reset()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?()
headlineBodyTextButton.headlineBody.styleListItem()
}
}

View File

@ -0,0 +1,57 @@
//
// LabelSwitch.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/26/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class LabelSwitch: ViewConstrainingView {
let label = Label.commonLabelB1(true)
let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault()
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
label.updateView(size)
mvmSwitch.updateView(size)
}
public override func setupView() {
super.setupView()
guard mvmSwitch.superview == nil else {
return
}
addSubview(label)
addSubview(mvmSwitch)
label.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
NSLayoutConstraint.pinSubviewsCenter(leftView: label, rightView: mvmSwitch)
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
label.setWithJSON(json?.optionalDictionaryForKey("label"), delegateObject: delegateObject, additionalData: additionalData)
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject)
}
public override func setAsMolecule() {
super.setAsMolecule()
label.setAsMolecule()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?()
label.styleB1(true)
}
public override func reset() {
super.reset()
label.reset()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?()
label.styleB1(true)
}
}

View File

@ -18,6 +18,42 @@ open class HeadlineBody: ViewConstrainingView {
var leftConstraintMessage: NSLayoutConstraint?
var rightConstraintMessage: NSLayoutConstraint?
func hasText() -> Bool {
return headlineLabel.hasText || messageLabel.hasText
}
// MARK: - Styling
func style(with styleString: String?) {
guard let styleString = styleString else {
return
}
switch styleString {
case "header":
stylePageHeader()
case "item":
styleListItem()
default: break
}
}
func styleLandingPageHeader() {
headlineLabel.styleH1(true)
messageLabel.styleB2(true)
spaceBetweenLabelsConstant = PaddingTwo
}
func stylePageHeader() {
headlineLabel.styleH2(true)
messageLabel.styleB2(true)
spaceBetweenLabelsConstant = PaddingTwo
}
func styleListItem() {
headlineLabel.styleB1(true)
messageLabel.styleB2(true)
spaceBetweenLabelsConstant = 0
}
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
@ -87,6 +123,8 @@ open class HeadlineBody: ViewConstrainingView {
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
style(with: json?.optionalStringForKey("style"))
let headlineJSON = json?.optionalDictionaryForKey("headline")
headlineLabel.setWithJSON(headlineJSON, delegateObject: delegateObject, additionalData: additionalData)
let bodyJSON = json?.optionalDictionaryForKey("body")
@ -95,9 +133,7 @@ open class HeadlineBody: ViewConstrainingView {
open override func reset() {
super.reset()
headlineLabel.styleH2(true)
messageLabel.styleB2(true)
spaceBetweenLabelsConstant = PaddingTwo
stylePageHeader()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {

View File

@ -0,0 +1,78 @@
//
// HeadlineBodyTextButton.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/28/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class HeadlineBodyTextButton: ViewConstrainingView {
let headlineBody = HeadlineBody(frame: .zero)
let textButton = MFTextButton(nil, constrainHeight: true, forWidth: MVMCoreUIUtility.getWidth())
var spaceBetweenConstant: CGFloat = 0.0
var spaceBetween: NSLayoutConstraint?
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
textButton.updateView(size)
setSpacing()
}
open override func setupView() {
super.setupView()
guard subviews.count == 0 else {
return
}
addSubview(headlineBody)
addSubview(textButton)
headlineBody.styleListItem()
headlineBody.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor, constant: 0).isActive = true
headlineBody.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true
var constraint = layoutMarginsGuide.rightAnchor.constraint(equalTo: headlineBody.rightAnchor)
constraint.priority = .defaultHigh
constraint.isActive = true
spaceBetween = textButton.topAnchor.constraint(equalTo: headlineBody.bottomAnchor, constant: spaceBetweenConstant)
spaceBetween?.isActive = true
textButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(equalTo: textButton.bottomAnchor).isActive = true
layoutMarginsGuide.rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor).isActive = true
constraint = layoutMarginsGuide.rightAnchor.constraint(equalTo: textButton.rightAnchor)
constraint.priority = .defaultHigh
constraint.isActive = true
}
// MARK: - Constraining
public func setSpacing() {
if headlineBody.hasText() && (textButton.titleLabel?.text?.count ?? 0) > 0 {
spaceBetween?.constant = spaceBetweenConstant
} else {
spaceBetween?.constant = 0
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData)
textButton.setWithJSON(json?.optionalDictionaryForKey("textButton"), delegateObject: delegateObject, additionalData: additionalData)
}
open override func reset() {
super.reset()
headlineBody.reset()
headlineBody.styleListItem()
textButton.reset()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 60
}
}

View File

@ -41,12 +41,11 @@
@"checkbox" : MVMCoreUICheckBox.class,
@"cornerLabels" : CornerLabels.class,
@"progressBar": ProgressBar.class,
@"textField": MFTextField.class,
@"checkbox": MVMCoreUICheckBox.class,
@"radioButton": RadioButton.class,
@"listItem": MoleculeTableViewCell.class,
@"switchLineItem": SwitchLineItem.class,
@"switch": Switch.class,
@"accordionListItem": AccordionMoleculeTableViewCell.class,
@"switch": MVMCoreUISwitch.class,
@"leftRightLabelView": LeftRightLabelView.class,
@"actionDetailWithImage": ActionDetailWithImage.class,
@"image": MFLoadImageView.class,
@ -56,7 +55,11 @@
@"carouselItem": MoleculeCollectionViewCell.class,
@"barsPager": MVMCoreUIPageControl.class,
@"scroller": Scroller.class,
@"imageHeadlineBody": ImageHeadlineBody.class
@"imageHeadlineBody": ImageHeadlineBody.class,
@"labelSwitch": LabelSwitch.class,
@"headlineBodySwitch": HeadlineBodySwitch.class,
@"headlineBodyTextButton": HeadlineBodyTextButton.class,
@"headlineBodyTextButtonSwitch": HeadlineBodyTextButtonSwitch.class
} mutableCopy];
});
return mapping;

View File

@ -16,4 +16,8 @@
/// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method.
- (void)moleculeLayoutUpdated:(nonnull UIView <MVMCoreUIMoleculeViewProtocol>*)molecule;
/// Asks the delegate to add or remove molecules.
- (void)addMolecules:(nonnull NSArray <NSDictionary *>*)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath;
- (void)removeMolecules:(nonnull NSArray <NSDictionary *>*)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath;
@end

View File

@ -94,6 +94,7 @@ B3 -> Legal
+ (CGFloat)defaultVerticalPaddingForSize:(CGFloat)size;
+ (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size;
+ (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size horizontal:(BOOL)horizontal vertical:(BOOL)vertical;
+ (void)setMarginsForView:(nullable UIView *)view size:(CGFloat)size defaultHorizontal:(BOOL)horizontal top:(CGFloat)top bottom:(CGFloat)bottom;
//-------------------------------------------------
// Returns the fonts for these styles. Scales them as needed by default

View File

@ -97,13 +97,20 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
}
+ (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size horizontal:(BOOL)horizontal vertical:(BOOL)vertical {
CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0;
CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing3 : 0;
[MVMCoreDispatchUtility performBlockOnMainThread:^{
CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0;
CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing3 : 0;
[MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:verticalPadding trailing:horizontalPadding bottom:verticalPadding];
}];
}
+ (void)setMarginsForView:(nullable UIView *)view size:(CGFloat)size defaultHorizontal:(BOOL)horizontal top:(CGFloat)top bottom:(CGFloat)bottom {
CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0;
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:top trailing:horizontalPadding bottom:bottom];
}];
}
#pragma mark - 2.0 fonts
+ (nullable UIFont *)fontH1:(BOOL)genericScaling {

View File

@ -8,6 +8,7 @@
//// Accessibility
"AccCloseButton" = "Close";
"swipe_to_select_with_action_hint" = "swipe up or down to select action, then double tap to select.";
// Tab
"AccTab" = ", tab";
"AccTabHint" = "Double tap to select.";

View File

@ -6,6 +6,9 @@
Copyright © 2017 myverizon. All rights reserved.
*/
// Accessibility
"swipe_to_select_with_action_hint" = "deslízate hacia arriba o hacia abajo para seleccionar la acción, luego toca dos veces para seleccionar.";
"AccCloseButton" = "Cerrar";
// Tab
"AccTab" = ", pestaña";

View File

@ -6,6 +6,9 @@
Copyright © 2017 myverizon. All rights reserved.
*/
// Accessibility
"swipe_to_select_with_action_hint" = "deslízate hacia arriba o hacia abajo para seleccionar la acción, luego toca dos veces para seleccionar.";
"AccCloseButton" = "Cerrar";
// Tab
"AccTab" = ", pestaña";

View File

@ -117,6 +117,36 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
}
}
open override func addMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) {
var indexPaths: [IndexPath] = []
var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = []
for (index, molecule) in molecules.enumerated() {
if let info = getMoleculeInfo(with: molecule) {
moleculeList.append(info)
indexPaths.append(IndexPath(row: indexPath.row + 1 + index, section: 0))
tableView?.register(info.class, forCellReuseIdentifier: info.identifier)
}
}
moleculesInfo?.insert(contentsOf: moleculeList, at: indexPath.row + 1)
tableView?.insertRows(at: indexPaths, with: .automatic)
}
open override func removeMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) {
guard let moleculesList = moleculesInfo else {
return
}
var indexPaths: [IndexPath] = []
for (index, moleculeInfo) in moleculesList.enumerated() {
if molecules.contains(where: { (molecule) -> Bool in
return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule)
}) {
indexPaths.append(IndexPath(row: index, section: 0))
moleculesInfo?.remove(at: index)
}
}
tableView?.deleteRows(at: indexPaths, with: .automatic)
}
// MARK: - Convenience
/// Returns the (identifier, class) of the molecule for the given map.
func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? {

View File

@ -173,6 +173,7 @@
if (closeButton && !self.closeButton) {
self.closeButton = [self addCloseButtonWithAnimationDelegate:animationDelegate];
[self.closeButton setTintColor:self.contentColor ?:[UIColor whiteColor]];
} else if (!closeButton && self.closeButton) {
[self.closeButton removeFromSuperview];
self.closeButton = nil;
@ -235,7 +236,7 @@
if (color) {
self.button.layer.borderColor = color.CGColor;
[self.button setTitleColor:color forState:UIControlStateNormal];
[self.closeButton setTitleColor:color forState:UIControlStateNormal];
[self.closeButton setTintColor:color];
}
}];
}

View File

@ -181,8 +181,9 @@ static const CGFloat VertialShadowOffset = 6;
+ (nonnull MFCustomButton *)addCloseButtonToView:(UIView *)view action:(ButtonTapBlock)actionBlock verticalCentered:(BOOL)verticalCentered {
MFCustomButton *button = [[MFCustomButton alloc] initWithFrame:CGRectZero];
button.translatesAutoresizingMaskIntoConstraints = NO;
[button setImage:[MVMCoreUIUtility imageNamed:@"closeXBlack"] forState:UIControlStateNormal];
button.titleLabel.font = [MFStyler fontForHeadlineAlternative];
UIImage *image = [[MVMCoreUIUtility imageNamed:@"closeXBlack"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[button setImage:image forState:UIControlStateNormal];
[button setTintColor:[UIColor blackColor]];
//accessibility
button.accessibilityLabel = [MVMCoreUIUtility hardcodedStringWithKey:@"AccCloseButton"];

View File

@ -119,7 +119,7 @@
#pragma mark - Sizing
+ (CGFloat)getWidth {
UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController;
UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController.navigationController ?: [MVMCoreUISession sharedGlobal].navigationController;
if (controller) {
return CGRectGetWidth(controller.view.bounds);
} else {