This commit is contained in:
Pfeil, Scott Robert 2019-11-05 08:50:17 -05:00
commit 0a45d61eb7
51 changed files with 922 additions and 358 deletions

View File

@ -7,10 +7,16 @@
objects = {
/* Begin PBXBuildFile section */
01004F3022721C3800991ECC /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01004F2F22721C3800991ECC /* RadioButton.swift */; };
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618A224BBE7700E1557D /* FormValidator.swift */; };
0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */; };
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */; };
016A1071228122180009D605 /* HeadlineBodyTextButtonSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016A1070228122180009D605 /* HeadlineBodyTextButtonSwitch.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 */; };
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB372360C6AC0024EF95 /* RadioButtonLabel.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 */; };
@ -24,8 +30,6 @@
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; };
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.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 */; };
@ -46,6 +50,7 @@
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */; };
D260D7B622D68514007E7233 /* MVMCoreUIPagingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274CA322236A78900B01B62 /* StandardFooterView.swift */; };
D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2755D7A23689C7500485468 /* TableViewCell.swift */; };
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */; };
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */; };
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */; };
@ -179,13 +184,14 @@
D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; };
D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B912361E65A00A9AEDC /* CoreUIObject.swift */; };
D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B93236214AD00A9AEDC /* NavigationController.swift */; };
D2B18B7F2360913400A9AEDC /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B7E2360913400A9AEDC /* Control.swift */; };
D2B18B812360945C00A9AEDC /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B802360945C00A9AEDC /* View.swift */; };
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */; };
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; };
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 */; };
@ -197,10 +203,16 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
01004F2F22721C3800991ECC /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
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 /* HeadlineBodyTextButtonSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButtonSwitch.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>"; };
017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabel.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>"; };
@ -213,8 +225,6 @@
0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = "<group>"; };
9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = "<group>"; };
948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.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>"; };
@ -235,6 +245,7 @@
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIPageControl.m; sourceTree = "<group>"; };
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPagingProtocol.h; sourceTree = "<group>"; };
D274CA322236A78900B01B62 /* StandardFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardFooterView.swift; sourceTree = "<group>"; };
D2755D7A23689C7500485468 /* TableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = "<group>"; };
D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewCell.swift; sourceTree = "<group>"; };
D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EyebrowHeadlineBodyLink.swift; sourceTree = "<group>"; };
D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFLoadImageView.swift; sourceTree = "<group>"; };
@ -372,13 +383,14 @@
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = "<group>"; };
D2B18B912361E65A00A9AEDC /* CoreUIObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreUIObject.swift; sourceTree = "<group>"; };
D2B18B93236214AD00A9AEDC /* NavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = "<group>"; };
D2B18B7E2360913400A9AEDC /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = "<group>"; };
D2B18B802360945C00A9AEDC /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = "<group>"; };
D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageHeadlineBody.swift; sourceTree = "<group>"; };
D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = "<group>"; };
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = "<group>"; };
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>"; };
@ -416,9 +428,9 @@
D224798823142BF2003FCCF9 /* SwitchMolecules */ = {
isa = PBXGroup;
children = (
01509D942327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift */,
D22479892314445E003FCCF9 /* LabelSwitch.swift */,
D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */,
016A1070228122180009D605 /* HeadlineBodyTextButtonSwitch.swift */,
);
path = SwitchMolecules;
sourceTree = "<group>";
@ -445,8 +457,8 @@
D224798F2316A99F003FCCF9 /* LeftRightViews */ = {
isa = PBXGroup;
children = (
01509D902327ECE600EF99AA /* CornerLabels.swift */,
D224798823142BF2003FCCF9 /* SwitchMolecules */,
B8200E182281DC1A007245F4 /* CornerLabels.swift */,
);
path = LeftRightViews;
sourceTree = "<group>";
@ -463,8 +475,9 @@
D22479912316A9EF003FCCF9 /* Items */ = {
isa = PBXGroup;
children = (
D2755D7A23689C7500485468 /* TableViewCell.swift */,
01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */,
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */,
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */,
D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */,
);
@ -504,6 +517,7 @@
D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */ = {
isa = PBXGroup;
children = (
D2B18B7D236090D500A9AEDC /* BaseClasses */,
01C74D87224298E2009C25A3 /* FormUIHelpers */,
D29DF31421ECECA7003B2FB9 /* SupportingFiles */,
D29DF27021E79B2C003B2FB9 /* OtherHandlers */,
@ -570,9 +584,11 @@
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */,
D2A514662213885800345BFB /* StandardHeaderView.swift */,
D274CA322236A78900B01B62 /* StandardFooterView.swift */,
0116A4E4228B19640094F3ED /* RadioButtonModel.swift */,
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */,
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */,
017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */,
);
path = Molecules;
sourceTree = "<group>";
@ -696,10 +712,10 @@
D29DF17D21E69E26003B2FB9 /* Views */ = {
isa = PBXGroup;
children = (
01509D922327ECFB00EF99AA /* ProgressBar.swift */,
D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */,
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */,
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */,
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
948DB67D2326DCD90011F916 /* MultiProgress.swift */,
DBC4391622442196001AB423 /* CaretView.swift */,
DBC4391722442197001AB423 /* DashLine.swift */,
@ -735,6 +751,7 @@
0198F7A22256A80A0066C936 /* MFRadioButton.m */,
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */,
0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */,
01004F2F22721C3800991ECC /* RadioButton.swift */,
);
path = Views;
sourceTree = "<group>";
@ -852,6 +869,15 @@
path = Strings;
sourceTree = "<group>";
};
D2B18B7D236090D500A9AEDC /* BaseClasses */ = {
isa = PBXGroup;
children = (
D2B18B7E2360913400A9AEDC /* Control.swift */,
D2B18B802360945C00A9AEDC /* View.swift */,
);
path = BaseClasses;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -1018,13 +1044,16 @@
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */,
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */,
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */,
01004F3022721C3800991ECC /* RadioButton.swift in Sources */,
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */,
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */,
D2B18B7F2360913400A9AEDC /* Control.swift in Sources */,
D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */,
DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */,
D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */,
@ -1041,15 +1070,17 @@
D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */,
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
D2755D7B23689C7500485468 /* TableViewCell.swift 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 */,
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */,
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */,
D2B18B812360945C00A9AEDC /* View.swift in Sources */,
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
@ -1059,8 +1090,8 @@
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */,
D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */,
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */,
D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */,
D29DF17A21E69E1F003B2FB9 /* MFCustomButton.m in Sources */,
@ -1075,7 +1106,6 @@
D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */,
D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */,
D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */,
016A1071228122180009D605 /* HeadlineBodyTextButtonSwitch.swift in Sources */,
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */,
D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */,
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
@ -1112,11 +1142,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

@ -64,7 +64,7 @@ import UIKit
primaryButton?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 42
}

View File

@ -140,7 +140,7 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol, MVMCoreUI
return UIStackView.Alignment.leading;
}
public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 10
}
}

View File

@ -13,13 +13,15 @@
#import "MFStyler.h"
#import "UIColor+MFConvenience.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
@import MVMCore.MVMCoreDispatchUtility;
@import MVMCore.MVMCoreGetterUtility;
@import MVMCore.NSDictionary_MFConvenience;
@interface PrimaryButton() <FormValidationProtocol>
@interface PrimaryButton() <FormValidationEnableDisableProtocol>
@property (nonatomic) BOOL validationRequired;
@property (nonatomic, strong) NSArray *requiredGroupsList;
@property (nonatomic) BOOL smallButton;
@property (assign, nonatomic) BOOL tinyButton;
@property (nonatomic) CGFloat sizeForSizing;
@ -666,6 +668,9 @@
}
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
self.validationRequired = [json boolForKey:@"validationRequired"];
self.requiredGroupsList = [json array:@"requiredGroups"];
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
self.primaryButtonType = PrimaryButtonTypeCustom;
@ -696,7 +701,6 @@
if ((color = [json string:@"disabledBorderColor"])) {
self.disabledBorderColor = [UIColor mfGetColorForHex:color];
}
self.validationRequired = [json boolForKey:@"validationRequired"];
NSString *size = [json string:@"size"];
if ([size isEqualToString:@"small"]) {
@ -773,7 +777,15 @@
}
}
#pragma mark - FormValidationProtocol
#pragma mark - FormValidationEnableDisableProtocol
- (BOOL)isValidationRequired {
return self.validationRequired;
}
- (NSArray<NSString *> *)requiredGroups {
return self.requiredGroupsList;
}
- (void)enableField:(BOOL)enable {
if (!self.validationRequired) {

View File

@ -46,7 +46,8 @@
// To set the placeholder and text
@property (nullable, weak, nonatomic) NSString *text;
@property (nullable, weak, nonatomic) NSString *formText;
@property (nullable, weak, nonatomic) NSString *fieldKey;
@property (nullable, strong, nonatomic) NSString *fieldKey;
@property (nullable, strong, nonatomic) NSString *groupName;
@property (nullable, weak, nonatomic) NSString *placeholder; // will move out in Feb release

View File

@ -18,7 +18,7 @@
@import MVMCore.NSDictionary_MFConvenience;
@import MVMCore.MVMCoreJSONConstants;
@interface MFTextField() <FormValidationProtocol>
@interface MFTextField() <FormValidationFormFieldProtocol>
@property (strong, nonatomic) UIColor *customPlaceHolderColor;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *separatorHeightConstraint;
@ -317,12 +317,14 @@
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"]) {
@ -586,5 +588,9 @@
- (nullable id)formFieldValue {
return self.text;
}
- (NSString * _Nullable)formFieldGroupName {
return self.groupName;
}
@end

View File

@ -19,7 +19,8 @@ import MVMCore
// Form Validation
var isRequired = false
var fieldKey: String?
var delegateObject: DelegateObject?
var groupName: String?
var delegateObject: MVMCoreUIDelegateObject?
public static let defaultHeightWidth: CGFloat = 18.0
@ -104,12 +105,8 @@ import MVMCore
layoutIfNeeded()
shapeLayer?.removeAllAnimations()
updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated)
if let delegate = delegateObject as? FormValidationProtocol {
delegate.formValidatorModel?()?.enableByValidation()
}
updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated)
FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol)
updateAccessibilityLabel()
}
}
@ -211,7 +208,6 @@ import MVMCore
/// This will toggle the state of the Checkbox and execute the actionBlock if provided.
public func toggleAndAction() {
isSelected.toggle()
actionBlock?()
}
@ -308,8 +304,9 @@ import MVMCore
/// Adjust accessibility label based on state of Checkbox.
func updateAccessibilityLabel() {
// Attention: This needs to be addressed with the accessibility team.
// NOTE: Currently emptying description part of MVMCoreUICheckBox accessibility label to avoid crashing!
if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") {
accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@", state)
accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@%@", "", state)
}
}
@ -408,7 +405,8 @@ import MVMCore
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
guard let dictionary = json else { return }
groupName = dictionary.optionalStringForKey("groupName")
if let fieldKey = dictionary[KeyFieldKey] as? String {
self.fieldKey = fieldKey
}
@ -462,7 +460,11 @@ import MVMCore
}
// MARK:- FormValidationProtocol
extension Checkbox: FormValidationProtocol {
extension Checkbox: FormValidationFormFieldProtocol {
public func formFieldGroupName() -> String? {
return groupName
}
public func isValidField() -> Bool {
return isRequired ? isSelected : true

View File

@ -37,10 +37,15 @@ public typealias ActionBlock = () -> ()
return !text.isEmpty || !attributedText.string.isEmpty
}
public var getRange: NSRange {
return NSRange(location: 0, length: text?.count ?? 0)
}
//------------------------------------------------------
// MARK: - Multi-Action Text
//------------------------------------------------------
/// Data store of the tappable ranges of the text.
public var clauses: [ActionableClause] = [] {
didSet {
isUserInteractionEnabled = !clauses.isEmpty
@ -112,6 +117,15 @@ public typealias ActionBlock = () -> ()
standardFontSize = size
}
/// Convenience to init Label with a link comprised of range, actionMap and delegateObject
@objc convenience public init(text: String, range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
self.init()
self.text = text
if let actionBlock = createActionBlockFor(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) {
setTextLinkState(range: range, actionBlock: actionBlock)
}
}
//------------------------------------------------------
// MARK: - Factory Functions
//------------------------------------------------------
@ -307,8 +321,9 @@ public typealias ActionBlock = () -> ()
guard let actionLabel = label as? Label else { continue }
actionLabel.addActionAttributes(range: range, string: attributedString)
let actionBlock = actionLabel.createActionBlockFrom(actionMap: attribute, additionalData: additionalData, delegateObject: delegate)
actionLabel.appendActionableClause(range: range, actionBlock: actionBlock)
if let actionBlock = actionLabel.createActionBlockFor(actionMap: attribute, additionalData: additionalData, delegateObject: delegate) {
actionLabel.appendActionableClause(range: range, actionBlock: actionBlock)
}
default:
continue
@ -483,7 +498,7 @@ public typealias ActionBlock = () -> ()
}
/// Call to detect in the attributedText contains an NSTextAttachment.
func textContainsTextAttachment() -> Bool {
func containsTextAttachment() -> Bool {
guard let attributedText = attributedText else { return false }
@ -588,7 +603,7 @@ extension Label {
}
}
// MARK: - Multi-Action Functionality
// MARK: - Multi-Link Functionality
extension Label {
/// Applied to existing text. Removes underlines of tappable links and assoated actionable clauses.
@ -607,15 +622,17 @@ extension Label {
clauses = []
}
public func createActionBlockFrom(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> ActionBlock {
public func createActionBlockFor(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> ActionBlock? {
return { [weak self] in
if let wSelf = self, (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate?.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
guard let self = self else { return }
if (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate?.button?(self, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
}
}
func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) {
private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) {
guard let string = string else { return }
string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range)
@ -639,8 +656,7 @@ extension Label {
*/
@objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) {
setActionAttributes(range: range)
appendActionableClause(range: range, actionBlock: actionBlock)
setTextLinkState(range: range, actionBlock: actionBlock)
}
/**
@ -654,15 +670,35 @@ extension Label {
*/
@objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
if let actionBlock = createActionBlockFor(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) {
setTextLinkState(range: range, actionBlock: actionBlock)
}
}
/// Converts the entire text into a link. All characters will be underlined and the intrinsic bounds will respond to tap.
@objc public func makeTextButton(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
if let actionBlock = createActionBlockFor(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) {
setTextLinkState(range: getRange, actionBlock: actionBlock)
}
}
/// Converts the entire text into a link. All characters will be underlined and the intrinsic bounds will respond to tap.
@objc public func makeTextButton(actionBlock: @escaping ActionBlock) {
setTextLinkState(range: getRange, actionBlock: actionBlock)
}
/// Underlines the tappable region and stores the tap logic for interation.
private func setTextLinkState(range: NSRange, actionBlock: @escaping ActionBlock) {
setActionAttributes(range: range)
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()
@ -686,9 +722,33 @@ extension UITapGestureRecognizer {
let textContainer = abstractContainer.0
let layoutManager = abstractContainer.1
let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer)
let tapLocation = location(in: label)
let indexOfGlyph = layoutManager.glyphIndex(for: tapLocation, in: textContainer)
let intrinsicWidth = label.intrinsicContentSize.width
return NSLocationInRange(indexOfGlyph, targetRange)
// Assert that tapped occured within acceptable bounds based on alignment.
switch label.textAlignment {
case .right:
if tapLocation.x < label.bounds.width - intrinsicWidth {
return false
}
case .center:
let halfBounds = label.bounds.width / 2
let halfIntrinsicWidth = intrinsicWidth / 2
if tapLocation.x > halfBounds + halfIntrinsicWidth {
return false
} else if tapLocation.x < halfBounds - halfIntrinsicWidth {
return false
}
default: // Left align
if tapLocation.x > intrinsicWidth {
return false
}
}
// Affirms that the tap occured in the desired rect of provided by the target range.
return layoutManager.boundingRect(forGlyphRange: targetRange, in: textContainer).contains(tapLocation) && NSLocationInRange(indexOfGlyph, targetRange)
}
}

View File

@ -207,7 +207,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
@objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
actionBlock = label?.createActionBlockFor(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
//------------------------------------------------------
@ -377,7 +377,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
actionText = actionMap?.optionalStringForKey(KeyTitle)
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
text = getTextFromStringComponents()
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
actionBlock = label?.createActionBlockFor(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
setLabelAttributes()
}

View File

@ -215,7 +215,7 @@ import UIKit
pinEdges(.all)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return json?.optionalCGFloatForKey("height") ?? 0
}

View File

@ -21,7 +21,7 @@
static const CGFloat FaultTolerance = 20.f;
static const CGFloat CheckBoxHeightWidth = 18.0;
@interface MVMCoreUICheckBox () <FormValidationProtocol, MVMCoreUIMoleculeViewProtocol>
@interface MVMCoreUICheckBox () <FormValidationFormFieldProtocol, MVMCoreUIMoleculeViewProtocol>
@property (nonatomic, readwrite) BOOL isSelected;
@property (weak, nonatomic) UIView *checkedSquare;
@ -42,7 +42,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
@property (nonatomic) BOOL isRequired;
@property (nullable, strong, nonatomic) NSString *fieldKey;
@property (nullable, strong, nonatomic) DelegateObject *delegate;
@property (nullable, strong, nonatomic) MVMCoreUIDelegateObject *delegateObject;
@end
@ -61,7 +61,8 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
self.delegate = delegateObject;
self.delegateObject = delegateObject;
self.fieldKey = [json stringForKey:KeyFieldKey];
self.isRequired = [json boolForKey:KeyRequired];
@ -347,10 +348,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
[self.checkMark updateCheckSelected:NO animated:animated];
}
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];
}
[FormValidator enableByValidationWithDelegate:self.delegateObject.formValidationProtocol];
}
- (void)setColor:(nullable UIColor *)color forState:(UIControlState)state {

View File

@ -24,6 +24,7 @@ typedef void(^ValueChangeBlock)(void);
@property (nonatomic) BOOL shouldTouchToSwitch;
@property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock;
@property (nullable, copy, nonatomic) ValueChangeBlock actionBlock;
+ (nonnull instancetype)mvmSwitchDefault;
+ (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block;

View File

@ -22,7 +22,7 @@ const CGFloat SwitchKnobWidth = 20;
const CGFloat SwitchKnobHeight = 20;
const CGFloat SwitchShakeIntensity = 2;
@interface MVMCoreUISwitch () <FormValidationProtocol, MVMCoreUIViewConstrainingProtocol>
@interface MVMCoreUISwitch () <FormValidationFormFieldProtocol, MVMCoreUIViewConstrainingProtocol>
@property (weak, nonatomic) UIView *baseView;
@property (weak, nonatomic) UIView *knobView;
@ -145,7 +145,8 @@ const CGFloat SwitchShakeIntensity = 2;
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
self.json = json;
self.delegate = delegateObject;
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
NSString *color = [json string:@"onTintColor"];
@ -169,6 +170,17 @@ const CGFloat SwitchShakeIntensity = 2;
}
[self setState:[json boolForKey:@"state"] animated:false];
NSDictionary *actionMap = [json dict:@"actionMap"];
if (actionMap) {
[self addTarget:self action:@selector(addCustomAction) forControlEvents:UIControlEventTouchUpInside];
}
}
- (void)addCustomAction {
if (self.actionBlock) {
self.actionBlock();
}
}
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {

View File

@ -73,7 +73,7 @@ import Foundation
trackTintColor = UIColor.mfLightSilver()
}
public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 8
}
}

View File

@ -0,0 +1,135 @@
//
// RadioButton.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 4/25/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class RadioButton: Control, FormValidationFormFieldProtocol {
var diameter: CGFloat = 30 {
didSet {
widthConstraint?.constant = diameter
}
}
var enabledColor = UIColor.black
var disabledColor = UIColor.mfSilver()
var delegateObject: MVMCoreUIDelegateObject?
var fieldKey: String?
var formValue: Bool?
var isRequired: Bool = false
var widthConstraint: NSLayoutConstraint?
var heightConstraint: NSLayoutConstraint?
lazy var radioGroupName: String? = {
[unowned self] in
return json?.optionalStringForKey("radioGroupName") ?? json?.optionalStringForKey("fieldKey")
}()
lazy var radioButtonModel: RadioButtonModel? = {
[unowned self] in
if let radioGroupName = radioGroupName,
let radioButtonModel = delegateObject?.formValidationProtocol?.formValidatorModel?()?.radioButtonsModelByGroup[radioGroupName] {
return radioButtonModel
} else {
return nil
}
}()
open override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
let color = isEnabled ? enabledColor.cgColor : disabledColor.cgColor
layer.cornerRadius = bounds.width * 0.5
layer.borderColor = color
layer.borderWidth = bounds.width * 0.0333
if isSelected {
// Space around inner circle is 1/5 the size
context.addEllipse(in: CGRect(x: bounds.width*0.2, y: bounds.height*0.2, width: bounds.width*0.6, height: bounds.height*0.6))
context.setFillColor(color)
context.fillPath()
}
}
/// The action performed when tapped.
func tapAction() {
if let radioButtonModel = radioButtonModel {
radioButtonModel.selected(self)
} else {
isSelected = !isSelected
}
FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol)
setNeedsDisplay()
}
public func isValidField() -> Bool {
return isSelected
}
public func formFieldName() -> String? {
return json?.optionalStringForKey("fieldKey")
}
public func formFieldGroupName() -> String? {
return json?.optionalStringForKey("groupName")
}
public func formFieldValue() -> Any? {
return isSelected
}
// MARK: - MVMViewProtocol
open override func setupView() {
super.setupView()
backgroundColor = .white
clipsToBounds = true
widthConstraint = widthAnchor.constraint(equalToConstant: 30)
widthConstraint?.isActive = true
heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1)
heightConstraint?.isActive = true
addTarget(self, action: #selector(tapAction), for: .touchUpInside)
isAccessibilityElement = true
accessibilityTraits = .button
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint")
}
}
// MARK: - MVMCoreUIViewConstrainingProtocol
extension RadioButton: MVMCoreUIViewConstrainingProtocol {
public func needsToBeConstrained() -> Bool {
return true
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
extension RadioButton {
@objc open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
// Configure class properties with JSON values
guard let jsonDictionary = json else {
return
}
fieldKey = jsonDictionary.optionalStringForKey("fieldKey")
isRequired = jsonDictionary.boolForKey("required")
self.delegateObject = delegateObject
let radioButtonModel = RadioButtonModel.setupForRadioButtonGroup(radioButton: self,
formValidator: delegateObject?.formValidationProtocol?.formValidatorModel?())
FormValidator.setupValidation(molecule: radioButtonModel, delegate: delegateObject?.formValidationProtocol)
}
public override func reset() {
super.reset()
backgroundColor = .white
}
}

View File

@ -0,0 +1,62 @@
//
// Control.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/23/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
public class Control: UIControl {
var json: [AnyHashable: Any]?
private var initialSetupPerformed = false
public override init(frame: CGRect) {
super.init(frame: .zero)
initialSetup()
}
init() {
super.init(frame: .zero)
initialSetup()
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
initialSetup()
}
public func initialSetup() {
if !initialSetupPerformed {
initialSetupPerformed = true
setupView()
}
}
}
extension Control: MVMCoreViewProtocol {
public func updateView(_ size: CGFloat) {
}
/// Will be called only once.
public func setupView() {
translatesAutoresizingMaskIntoConstraints = false
insetsLayoutMarginsFromSafeArea = false
}
}
extension Control: MVMCoreUIMoleculeViewProtocol {
public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
self.json = json
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
}
}
public func reset() {
backgroundColor = .clear
}
}

View File

@ -0,0 +1,61 @@
//
// View.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 10/23/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class View: UIView {
open var json: [AnyHashable: Any]?
private var initialSetupPerformed = false
public override init(frame: CGRect) {
super.init(frame: .zero)
initialSetup()
}
public init() {
super.init(frame: .zero)
initialSetup()
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
initialSetup()
}
public func initialSetup() {
if !initialSetupPerformed {
initialSetupPerformed = true
setupView()
}
}
}
extension View: MVMCoreViewProtocol {
open func updateView(_ size: CGFloat) {}
/// Will be called only once.
open func setupView() {
translatesAutoresizingMaskIntoConstraints = false
insetsLayoutMarginsFromSafeArea = false
}
}
extension View: MVMCoreUIMoleculeViewProtocol {
open func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
self.json = json
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
}
}
open func reset() {
backgroundColor = .clear
}
}

View File

@ -214,14 +214,16 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
/// Subclass for a top view.
open func viewForTop() -> UIView {
let view = MVMCoreUICommonViewsUtility.commonView()
view.heightAnchor.constraint(equalToConstant: 0).isActive = true
// Small height is needed to stop apple from adding padding for grouped tables when no header.
view.heightAnchor.constraint(equalToConstant: 1).isActive = true
return view
}
/// Subclass for a bottom view.
open func viewForBottom() -> UIView {
// Default spacing is standard when no buttons.
let view = MVMCoreUICommonViewsUtility.commonView()
view.heightAnchor.constraint(equalToConstant: 0).isActive = true
view.heightAnchor.constraint(equalToConstant: PaddingDefaultVerticalSpacing).isActive = true
return view
}

View File

@ -0,0 +1,61 @@
//
// ViewController.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 11/5/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class ViewController: UIViewController, MVMCoreViewControllerProtocol {
public var pageType: String?
public var loadObject: MVMCoreLoadObject?
// MARK: - Response handling
public func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
pageType = loadObject.pageType
self.loadObject = loadObject
// Verifies all modules needed are loaded.
return MFViewController.verifyRequiredModulesLoaded(for: loadObject, error: error)
}
public class func verifyRequiredModulesLoaded(for loadObject: MVMCoreLoadObject?, error: inout MVMCoreErrorObject?) -> Bool {
guard let pageType = loadObject?.pageType, var modulesRequired = MVMCoreUIViewControllerMappingObject.shared()?.modulesRequired(forPageType: pageType) else { return true }
guard let loadedModules = loadObject?.modulesJSON else { return false }
for case let key as String in Array(loadedModules.keys) {
guard modulesRequired.count > 0 else { break }
if let index = modulesRequired.firstIndex(where: {($0 as? String) == key}), index != NSNotFound {
modulesRequired.remove(at: index)
}
}
guard modulesRequired.count == 0 else {
if error != nil {
error = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorCritical), messageToLog: modulesRequired.description, code: ErrorCode.requiredModuleNotPresent.rawValue, domain: ErrorDomainNative, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject!))
}
return false
}
return true
}
open func newDataBuildScreen() {
// TODO- tell navigation object to update with model
}
open func initialLoad() {
}
open func updateViews() {
}
override open func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

View File

@ -1,28 +0,0 @@
//
// MVMCoreUINavigationController.h
// MVMCoreUI
//
// Created by Scott Pfeil on 1/25/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
#import <UIKit/UIKit.h>
@class SeparatorView;
NS_ASSUME_NONNULL_BEGIN
@interface MVMCoreUINavigationController : UINavigationController
// Convenience getter
+ (nullable instancetype)navigationController;
// Returns a navigation controller with the mvm styling. Also sets the navigation controller in the appropriate handlers.
+ (nullable instancetype)setupNavigationController;
// Returns a navigation controller with the mvm styling. Also sets the navigation controller in the appropriate handlers. Adds the default loading overlay screen as well.
+ (nullable instancetype)setupWithNavigationControllerAsMainController;
// Separator at the bottom of the navigation bar used for styling.
@property (nullable, weak, nonatomic) SeparatorView *separatorView;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,52 +0,0 @@
//
// MVMCoreUINavigationController.m
// MVMCoreUI
//
// Created by Scott Pfeil on 1/25/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
#import "MVMCoreUINavigationController.h"
#import "UIColor+MFConvenience.h"
#import "SeparatorView.h"
#import "MFFonts.h"
#import "MFSizeObject.h"
#import "MVMCoreUISession.h"
@import MVMCore.MVMCoreActionUtility;
@import MVMCore.MVMCoreNavigationHandler;
@interface MVMCoreUINavigationController ()
@end
@implementation MVMCoreUINavigationController
+ (nullable instancetype)navigationController {
return [MVMCoreActionUtility initializerClassCheck:[MVMCoreUISession sharedGlobal].navigationController classToVerify:self];
}
+ (nullable instancetype)setupNavigationController {
MVMCoreUINavigationController *navigationController = [[MVMCoreUINavigationController alloc] init];
[UIColor mfSetBackgroundColorForNavigationBar:[UIColor whiteColor] navigationBar:navigationController.navigationBar transparent:NO];
[navigationController.navigationBar setShadowImage:[[UIImage alloc] init]];
navigationController.navigationBar.translucent = NO;
navigationController.navigationBar.opaque = YES;
navigationController.navigationBar.tintColor = [UIColor blackColor];
navigationController.separatorView = [SeparatorView separatorAddToView:navigationController.navigationBar position:SeparatorPositionBot withHorizontalPadding:0];
[navigationController.separatorView setAsLight];
[navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName:[MFFonts mfFont75Bd:[[MFSizeObject sizeObjectWithStandardSize:14 standardiPadPortraitSize:16 iPadProLandscapeSize:18] getValueBasedOnScreenSize]]}];
// Set standard
[MVMCoreUISession sharedGlobal].navigationController = navigationController;
[MVMCoreNavigationHandler sharedNavigationHandler].navigationController = navigationController;
[MVMCoreNavigationHandler sharedNavigationHandler].viewControllerToPresentOn = navigationController;
return navigationController;
}
+ (nullable instancetype)setupWithNavigationControllerAsMainController {
MVMCoreUINavigationController *navigationController = [self setupNavigationController];
[[MVMCoreUISession sharedGlobal] setupAsStandardLoadViewDelegate:navigationController];
return navigationController;
}
@end

View File

@ -10,18 +10,32 @@ import Foundation
@objc public protocol FormValidationProtocol: NSObjectProtocol {
// Getter method to get the FormValidator form the delegate (Mostly from the parent View Controller)
// Getter method to get the FormValidator from the delegate (Mostly from the parent View Controller)
@objc optional func formValidatorModel() -> FormValidator?
}
@objc public protocol FormValidationFormFieldProtocol: FormValidationProtocol {
// Used to check the validity of the field. For example, to enable/disable the primary button.
@objc func isValidField() -> Bool
// Used to check the validity of the field, to enable/disable the primary button.
@objc optional func isValidField() -> Bool
// The Field name key value pair for sending to server
@objc func formFieldName() -> String?
// Returns the group name for validation. The class should always return a value.
@objc func formFieldGroupName() -> String?
// The Field value key value pair for sending to server
@objc func formFieldValue() -> Any?
}
@objc public protocol FormValidationEnableDisableProtocol: FormValidationProtocol {
// Returns true if the button needs to be enabled/disabled based on the validation
@objc func isValidationRequired() -> Bool
// Based on the isValidField(), the fields which needs to be enabled can call this method
@objc optional func enableField(_ enable: Bool)
// The Field name key value pair for sending to server
@objc optional func formFieldName() -> String?
// The Field value key value pair for sending to server
@objc optional func formFieldValue() -> Any?
// Returns the list of field keys required to enable/disable
@objc optional func requiredGroups() -> [String]?
}

View File

@ -16,13 +16,10 @@ import Foundation
@objc func getFormParams() -> [String: Any] {
var extraParam: [String: Any] = [:]
MVMCoreDispatchUtility.performSyncBlock(onMainThread: {
for molecule in self.molecules {
if let formFieldName = molecule.formFieldName,
let formFieldValue = molecule.formFieldValue,
let fieldName = formFieldName(),
let fieldValue = formFieldValue() {
extraParam[fieldName] = fieldValue
for molecule in self.fieldMolecules {
if let formFieldName = molecule.formFieldName(),
let formFieldValue = molecule.formFieldValue() {
extraParam[formFieldName] = formFieldValue
}
}
})

View File

@ -8,52 +8,79 @@
import Foundation
import UIKit
import MVMCore
@objcMembers public class FormValidator: NSObject {
var delegate: FormValidationProtocol?
var molecules: [UIView & FormValidationProtocol] = []
var extraValidationBlock: (() -> Bool)?
var dummyGroupName = "dummyGroupName"
weak var delegate: FormValidationProtocol?
var fieldMolecules: [FormValidationFormFieldProtocol] = []
var enableDisableMolecules: [FormValidationEnableDisableProtocol] = []
var radioButtonsModelByGroup: [String: RadioButtonModel] = [:]
public func insertMolecule(_ molecule: UIView & FormValidationProtocol) {
molecules.append(molecule)
public func insertMolecule(_ molecule: FormValidationProtocol) {
if let molecule = molecule as? FormValidationFormFieldProtocol {
fieldMolecules.append(molecule)
}
if let moleculeT = molecule as? FormValidationEnableDisableProtocol,
moleculeT.isValidationRequired() {
enableDisableMolecules.append(moleculeT)
}
}
public static func getFormValidatorFor(delegate: FormValidationProtocol) -> FormValidator? {
if let delegateFormValidatorModel = delegate.formValidatorModel,
let validator = delegateFormValidatorModel() {
return validator
} else {
return nil
public static func enableByValidationWith(delegate: FormValidationProtocol?) {
if let delegate = delegate {
let formValidator = FormValidator.getFormValidatorFor(delegate: delegate)
formValidator?.enableByValidation()
}
}
public static func setupValidation(molecule: UIView & FormValidationProtocol, delegate: FormValidationProtocol?) {
if let delegateFormValidatorModel = delegate?.formValidatorModel,
let validator = delegateFormValidatorModel() {
public static func getFormValidatorFor(delegate: FormValidationProtocol) -> FormValidator? {
return delegate.formValidatorModel?()
}
public static func setupValidation(molecule: FormValidationProtocol, delegate: FormValidationProtocol?) {
if let validator = delegate?.formValidatorModel?() {
validator.delegate = delegate
validator.insertMolecule(molecule)
}
}
public func enableByValidation() {
for molecule in enableDisableMolecules {
var requiredGroups = molecule.requiredGroups?() ?? [dummyGroupName]
if requiredGroups.count == 0 {
requiredGroups = [dummyGroupName]
}
enableWithGroups(requiredGroups, molecule)
}
}
public func enableWithGroups(_ requiredGroupList: [String], _ enableDisableMolecule: FormValidationEnableDisableProtocol) {
let requiredGroupSet = Set(requiredGroupList)
var valid = true
for molecule in molecules {
if let isValidField = molecule.isValidField,
isValidField() == false {
valid = false
for molecule in fieldMolecules {
let groupName = molecule.formFieldGroupName() ?? dummyGroupName
if requiredGroupSet.contains(groupName) {
valid = valid && molecule.isValidField()
if valid == false {
break
}
}
}
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)
shouldEnable(enableField)
}
public func shouldEnable(_ enable: Bool) {
for molecule in molecules {
if let enableField = molecule.enableField {
enableField(enable)
}
}
enableDisableMolecules.enableField?(enableField)
}
}

View File

@ -330,7 +330,7 @@
bottomViewBot.active = YES;
UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view];
safeAreaView.backgroundColor = footerView.backgroundColor;
safeAreaView.backgroundColor = self.bottomView.backgroundColor;
self.safeAreaView = safeAreaView;
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[footerView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(footerView)]];

View File

@ -91,7 +91,7 @@ import UIKit
imageLoader.updateView(size)
}
public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 197
}

View File

@ -82,7 +82,7 @@ import UIKit
imageView.reset()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 95
}
}

View File

@ -115,7 +115,7 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi
backgroundColor = .white
}
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
public class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
return nil
}

View File

@ -1,15 +1,14 @@
//
// MoleculeTableViewCell.swift
// TableViewCell.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 4/18/19.
// Created by Scott Pfeil on 10/29/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol {
@objcMembers open class TableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol {
open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)?
open var json: [AnyHashable: Any]?
@ -17,7 +16,7 @@ import UIKit
open var updateViewHorizontalDefaults = true
// For the accessory view convenience.
public var caretView: CaretView?
private var caretView: CaretView?
private var caretViewWidthSizeObject: MFSizeObject?
private var caretViewHeightSizeObject: MFSizeObject?
@ -25,20 +24,22 @@ import UIKit
public var topSeparatorView: SeparatorView?
public var bottomSeparatorView: SeparatorView?
public enum SeparatorFrequency: String {
case All = "all"
case AllExceptTop = "allExceptTop"
case AllExceptBottom = "allExceptBottom"
case Between = "between"
case all
case allExceptTop
case allExceptBottom
case 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
open var topMarginPadding: CGFloat = 24
open var bottomMarginPadding: CGFloat = 24
private var heroAccessoryCenter: CGPoint?
// MARK: - Styling
func style(with styleString: String?) {
open func style(with styleString: String?) {
guard let styleString = styleString else {
return
}
@ -53,6 +54,40 @@ import UIKit
}
}
open func styleStandard() {
topMarginPadding = 24
bottomMarginPadding = 24
bottomSeparatorView?.show()
bottomSeparatorView?.setAsLight()
}
open func styleHeader() {
topMarginPadding = 48
bottomMarginPadding = 16
bottomSeparatorView?.show()
bottomSeparatorView?.setAsRegular()
}
open func styleNone() {
topMarginPadding = 0
bottomMarginPadding = 0
bottomSeparatorView?.hide()
}
/// Adds the molecule to the view.
open func addMolecule(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) {
contentView.addSubview(molecule)
let standardConstraints = (molecule as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: molecule, useMargins: standardConstraints).values))
// This molecule will by default handle margins.
if let castView = molecule as? MVMCoreUIViewConstrainingProtocol {
castView.shouldSetHorizontalMargins?(false)
castView.shouldSetVerticalMargins?(false)
}
self.molecule = molecule
}
open override func layoutSubviews() {
super.layoutSubviews()
@ -62,33 +97,6 @@ import UIKit
}
}
var heroAccessoryCenter: CGPoint?
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()
}
public func willDisplay() {
alignAccessoryToHero()
}
// MARK: - Inits
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
@ -129,6 +137,83 @@ import UIKit
contentView.preservesSuperviewLayoutMargins = false
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
self.json = json
guard let json = json else { return }
style(with: json.optionalStringForKey("style"))
if let useHorizontalMargins = json.optionalBoolForKey("useHorizontalMargins") {
updateViewHorizontalDefaults = useHorizontalMargins
}
if (json.optionalBoolForKey("useVerticalMargins") ?? true) == false {
topMarginPadding = 0
bottomMarginPadding = 0
}
if let backgroundColorString = json.optionalStringForKey(KeyBackgroundColor) {
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
}
// Add the caret if there is an action and it's not declared hidden.
if !customAccessoryView {
if let _ = json.optionalDictionaryForKey("actionMap"), !json.boolForKey("hideArrow") {
addCaretViewAccessory()
} else {
accessoryView = nil
}
}
// override the separator
if let separator = json.optionalDictionaryForKey("separator") {
addSeparatorsIfNeeded()
bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData)
}
guard let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return }
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
// This molecule will by default handle margins.
if let castView = molecule as? MVMCoreUIViewConstrainingProtocol {
castView.shouldSetHorizontalMargins?(false)
castView.shouldSetVerticalMargins?(false)
}
}
public func reset() {
molecule?.reset?()
updateViewHorizontalDefaults = true
styleStandard()
backgroundColor = .white
}
public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else {
return 80
}
return max(2 * PaddingDefaultVerticalSpacing3, height)
}
public class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
return molecule?.optionalStringForKey(KeyMoleculeName) ?? ""
}
// MARK: - Arrow
/// Adds the standard mvm style caret to the accessory view
@objc public func addCaretViewAccessory() {
guard accessoryView == nil else { return }
let width: CGFloat = 6
let height: CGFloat = 10
caretView = CaretView(lineThickness: CaretView.thin)
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
caretViewWidthSizeObject = MFSizeObject(standardSize: width, standardiPadPortraitSize: 9)
caretViewHeightSizeObject = MFSizeObject(standardSize: height, standardiPadPortraitSize: 16)
accessoryView = caretView
}
/// NOTE: Should only be called when displayed or about to be displayed.
public func alignAccessoryToHero() {
@ -160,103 +245,6 @@ import UIKit
return findHeroLabel(views: queue)
}
// MARK: - MVMCoreUIMoleculeViewProtocol
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 (json?.optionalBoolForKey("useVerticalMargins") ?? true) == false {
topMarginPadding = 0
bottomMarginPadding = 0
}
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
}
// Add the caret if there is an action and it's not declared hidden.
if !customAccessoryView {
if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") {
addCaretViewAccessory()
} else {
accessoryView = nil
}
}
// override the separator
if let separator = json?.optionalDictionaryForKey("separator") {
addSeparatorsIfNeeded()
bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData)
}
guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return }
if molecule == nil {
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
contentView.addSubview(moleculeView)
let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
molecule = moleculeView
}
} else {
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
}
// This molecule will by default handle margins.
if let castView = molecule as? MVMCoreUIViewConstrainingProtocol {
castView.shouldSetHorizontalMargins?(false)
castView.shouldSetVerticalMargins?(false)
}
}
public func reset() {
molecule?.reset?()
updateViewHorizontalDefaults = true
styleStandard()
backgroundColor = .white
}
public static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else {
return 80
}
return max(2 * PaddingDefaultVerticalSpacing3, height)
}
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
return "\(self)<>"
}
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]? {
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else {
return nil
}
return theClass.requiredModules?(moleculeJSON, delegateObject: delegateObject, error: error)
}
// MARK: - Arrow
/// Adds the standard mvm style caret to the accessory view
@objc public func addCaretViewAccessory() {
guard accessoryView == nil else { return }
let width: CGFloat = 6
let height: CGFloat = 10
caretView = CaretView(lineThickness: CaretView.thin)
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
caretViewWidthSizeObject = MFSizeObject(standardSize: width, standardiPadPortraitSize: 9)
caretViewHeightSizeObject = MFSizeObject(standardSize: height, standardiPadPortraitSize: 16)
accessoryView = caretView
}
// MARK: - MoleculeListCellProtocol
/// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop.
public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) {
@ -270,7 +258,7 @@ import UIKit
} else {
topSeparatorView?.hide()
bottomSeparatorView?.setAsLight()
setSeparatorFrequency(MoleculeTableViewCell.SeparatorFrequency.AllExceptTop, indexPath: indexPath)
setSeparatorFrequency(TableViewCell.SeparatorFrequency.allExceptTop, indexPath: indexPath)
}
}
@ -280,8 +268,12 @@ import UIKit
}
}
public func willDisplay() {
alignAccessoryToHero()
}
// MARK: - Separator
func addSeparatorsIfNeeded() {
open func addSeparatorsIfNeeded() {
if topSeparatorView == nil {
topSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionTop)
topSeparatorView?.hide()
@ -295,24 +287,24 @@ import UIKit
/// For when the separator between cells shows.
public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) {
switch separatorFrequency {
case .All:
case .all:
if indexPath.row == 0 {
topSeparatorView?.show()
} else {
topSeparatorView?.hide()
}
bottomSeparatorView?.show()
case .AllExceptBottom:
case .allExceptBottom:
topSeparatorView?.show()
bottomSeparatorView?.hide()
case .Between:
case .between:
if indexPath.row == 0 {
topSeparatorView?.hide()
} else {
topSeparatorView?.show()
}
bottomSeparatorView?.hide()
case .AllExceptTop:
case .allExceptTop:
fallthrough
default:
topSeparatorView?.hide()

View File

@ -8,7 +8,7 @@
import UIKit
@objcMembers public class TabsTableViewCell: MoleculeTableViewCell {
@objcMembers public class TabsTableViewCell: TableViewCell {
let tabs = TopTabbar(frame: .zero)
var delegateObject: MVMCoreUIDelegateObject?
var previousTabIndex = 0

View File

@ -174,7 +174,7 @@ import UIKit
bottomRightLabel.styleB3(true)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 34
}
}

View File

@ -8,9 +8,9 @@
import UIKit
@objcMembers public class HeadlineBodySwitch: ViewConstrainingView {
let headlineBody = HeadlineBody(frame: .zero)
let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault()
@objcMembers open class HeadlineBodySwitch: ViewConstrainingView {
public let headlineBody = HeadlineBody(frame: .zero)
public let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault()
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
@ -19,7 +19,7 @@ import UIKit
mvmSwitch.updateView(size)
}
public override func setupView() {
open override func setupView() {
super.setupView()
guard mvmSwitch.superview == nil else {
return
@ -35,24 +35,24 @@ import UIKit
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
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)
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 30
}
public override func setAsMolecule() {
open override func setAsMolecule() {
super.setAsMolecule()
headlineBody.setAsMolecule()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?()
headlineBody.styleListItem()
}
public override func reset() {
open override func reset() {
super.reset()
headlineBody.reset()
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?()

View File

@ -41,7 +41,7 @@ import UIKit
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return HeadlineBodyTextButton.estimatedHeight(forRow: json, delegateObject: delegateObject)
}

View File

@ -41,7 +41,7 @@ import UIKit
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject)
}

View File

@ -54,7 +54,7 @@ open class ModuleMolecule: ViewConstrainingView {
moduleMolecule?.reset?()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
// Critical error
return 0
@ -62,7 +62,7 @@ open class ModuleMolecule: ViewConstrainingView {
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0
}
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
public override class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
guard let moduleName = molecule?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
// Critical error
return "moduleMolecule<>"
@ -70,7 +70,7 @@ open class ModuleMolecule: ViewConstrainingView {
return "moduleMolecule<" + (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.name?(forReuse: module, delegateObject: delegateObject) ?? module.stringForkey(KeyMoleculeName)) + ">"
}
public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
let moduleName = json?.optionalStringForKey("moduleName")
if moduleName == nil || delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) == nil {
if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) {

View File

@ -0,0 +1,90 @@
//
// RadioButtonWithLabel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 10/21/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class RadioButtonLabel: ViewConstrainingView {
public let radioButton = RadioButton()
var delegateObject: MVMCoreUIDelegateObject?
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)
}
public override func updateView(_ size: CGFloat) {
super.updateView(size)
radioButton.updateView(size)
label.updateView(size)
}
open override func setupView() {
super.setupView()
guard subviews.count == 0 else {
return
}
addSubview(radioButton)
radioButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor, constant: 0).isActive = true
radioButton.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor, constant: PaddingOne).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: radioButton.bottomAnchor, constant: PaddingOne).isActive = true
radioButton.centerYAnchor.constraint(equalTo: layoutMarginsGuide.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(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor, constant: PaddingOne)
constraint.priority = .defaultHigh
constraint.isActive = true
constraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: rightView.bottomAnchor, constant: PaddingOne)
constraint.priority = .defaultHigh
constraint.isActive = true
layoutMarginsGuide.centerYAnchor.constraint(equalTo: rightView.centerYAnchor).isActive = true
}
}
func createRightView() -> ViewConstrainingView? {
let rightView = ViewConstrainingView(constrainingView: label)
return rightView
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
extension RadioButtonLabel {
@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?.optionalDictionaryForKey("radioButton"), delegateObject: delegateObject, additionalData: additionalData)
label.setWithJSON(json?.optionalDictionaryForKey(KeyLabel),
delegateObject: delegateObject,
additionalData: additionalData)
}
public override func reset() {
super.reset()
radioButton.reset()
label.reset()
}
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 45
}
}

View File

@ -0,0 +1,54 @@
//
// RadioButtonModel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 5/14/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import Foundation
import UIKit
@objcMembers public class RadioButtonModel: NSObject {
private var selectedRadioButton: RadioButton?
private var fieldGroupName: String?
public static func setupForRadioButtonGroup(radioButton: RadioButton, formValidator: FormValidator?) -> RadioButtonModel {
guard let groupName = radioButton.radioGroupName,
let formValidator = formValidator else {
return RadioButtonModel()
}
let radioButtonModel = formValidator.radioButtonsModelByGroup[groupName] ?? RadioButtonModel()
radioButtonModel.fieldGroupName = radioButton.formFieldGroupName()
formValidator.radioButtonsModelByGroup[groupName] = radioButtonModel
return radioButtonModel
}
public func selected(_ radioButton: RadioButton) {
selectedRadioButton?.isSelected = false
selectedRadioButton = radioButton
selectedRadioButton?.isSelected = true
}
}
// MARK: - FormValidationFormFieldProtocol
extension RadioButtonModel: FormValidationFormFieldProtocol {
public func formFieldGroupName() -> String? {
return selectedRadioButton?.formFieldGroupName() ?? self.fieldGroupName
}
// Used to check the validity of the field, to enable/disable the primary button.
@objc public func isValidField() -> Bool {
return selectedRadioButton != nil ? true : false
}
// Name of the field to send to server
@objc public func formFieldName() -> String? {
return selectedRadioButton?.fieldKey
}
// The field value key value pair for sending to server
@objc public func formFieldValue() -> Any? {
return selectedRadioButton != nil ? true : false
}
}

View File

@ -26,7 +26,7 @@ open class StandardFooterView: ViewConstrainingView {
(molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
if let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) {
return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
}

View File

@ -62,7 +62,7 @@ public class StandardHeaderView: ViewConstrainingView {
separatorView?.show()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
if let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) {
return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
}

View File

@ -64,7 +64,7 @@ import UIKit
body.styleB2(true)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 65
}
}

View File

@ -136,7 +136,7 @@ open class HeadlineBody: ViewConstrainingView {
stylePageHeader()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 58
}
}

View File

@ -76,7 +76,7 @@ import UIKit
textButton.reset()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 60
}
}

View File

@ -184,7 +184,7 @@ public class MoleculeStackView: ViewConstrainingView {
}
}
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
public override class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
// This will aggregate names of molecules to make an id.
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
return "stack<>"
@ -199,7 +199,7 @@ public class MoleculeStackView: ViewConstrainingView {
return name
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
return 0
}
@ -221,7 +221,7 @@ public class MoleculeStackView: ViewConstrainingView {
return estimatedHeight
}
public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
return nil
}

View File

@ -26,7 +26,7 @@
dispatch_once(&onceToken, ^{
mapping = [@{
@"label": Label.class,
@"separator": SeparatorView.class,
@"line": SeparatorView.class,
@"button": ButtonView.class,
@"textButton": MFTextButton.class,
@"header": StandardHeaderView.class,
@ -40,8 +40,11 @@
@"checkbox" : Checkbox.class,
@"checkboxWithLabelView" : CheckboxWithLabelView.class,
@"cornerLabels" : CornerLabels.class,
@"progressBar": ProgressBar.class,
@"progressbar": ProgressBar.class,
@"multiProgressBar": MultiProgress.class,
@"checkbox": MVMCoreUICheckBox.class,
@"radioButton": RadioButton.class,
@"radioButtonLabel": RadioButtonLabel.class,
@"listItem": MoleculeTableViewCell.class,
@"accordionListItem": AccordionMoleculeTableViewCell.class,
@"switch": MVMCoreUISwitch.class,

View File

@ -36,6 +36,7 @@ extern CGFloat const PaddingHorizontalLarge;
extern CGFloat const PaddingVerticalWhiteGrayView;
extern CGFloat const PaddingVerticalHeadlineAlternate;
extern CGFloat const PaddingPrimaryButtonTop;
extern CGFloat const PaddingHorizontalBetweenRelatedItems;
// These are based on the multiple of 6 rule
extern CGFloat const PaddingOne;

View File

@ -26,6 +26,7 @@ CGFloat const PaddingVerticalWhiteGrayView = 72;
CGFloat const PaddingVerticalHeadlineAlternate = 48;
CGFloat const PaddingPrimaryButtonTop = 36;
CGFloat const PaddingHorizontalBetweenRelatedItems = 16;
CGFloat const PaddingOne = 6;
CGFloat const PaddingTwo = 12;
CGFloat const PaddingThree = 18;

View File

@ -36,6 +36,13 @@
"checkbox_checked_state" = "Checked";
"checkbox_unchecked_state" = "Unchecked";
"checkbox_desc_state" = "%@ CheckBox %@";
// Radio Button
"radio_action_hint" = "Double tap to select";
"radio_selected_state" = "Selected";
"radio_not_selected_state" = "Not Selected";
"radio_desc_state" = "Option";
// Switch
"mfswitch_buttonlabel" = "Switch Button";
"AccOn" = "on";

View File

@ -37,6 +37,11 @@
"checkbox_checked_state" = "Verificado";
"checkbox_unchecked_state" = "Sin marcar";
"checkbox_desc_state" = "%@ Casilla %@";
// Radio Button
"radio_action_hint" = "Toca dos veces para seleccionar.";
"radio_selected_state" = "Seleccionado";
"radio_not_selected_state" = "No Seleccionado";
"radio_desc_state" = "Opción";
// Switch
"mfswitch_buttonlabel" = "Botón Cambiar";
"AccOn" = "encendido";

View File

@ -37,6 +37,13 @@
"checkbox_checked_state" = "Verificado";
"checkbox_unchecked_state" = "Sin marcar";
"checkbox_desc_state" = "%@ Casilla %@";
// Radio Button
"radio_action_hint" = "Toca dos veces para seleccionar.";
"radio_selected_state" = "Seleccionado";
"radio_not_selected_state" = "No Seleccionado";
"radio_desc_state" = "Opción";
// Switch
"mfswitch_buttonlabel" = "Botón Cambiar";
"AccOn" = "encendido";

View File

@ -126,7 +126,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) {
// This dispatch is needed to fix a race condition that can occur if this function is called during the table setup.
DispatchQueue.main.async {
guard let cell = sender as? MoleculeTableViewCell, let indexPath = self.tableView?.indexPath(for: cell) else { return }
guard let indexPath = self.tableView?.indexPath(for: sender) else { return }
var indexPaths: [IndexPath] = []
for molecule in molecules {
if let info = self.getMoleculeInfo(with: molecule) {

View File

@ -33,6 +33,7 @@ static const CGFloat VertialShadowOffset = 6;
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.backgroundColor = [UIColor clearColor];
view.directionalLayoutMargins = NSDirectionalEdgeInsetsZero;
return view;
}