diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index e2b1e234..ce9d4f1c 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -11,10 +11,12 @@ 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 */; }; 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, ); }; }; @@ -35,6 +37,9 @@ D282AACB2243C61700C46919 /* ButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AACA2243C61700C46919 /* ButtonView.swift */; }; D28B4F8A21FF967C00712C7A /* MVMCoreUIObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D28B4F8821FF967C00712C7A /* MVMCoreUIObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */; }; + D296E13C229598BF0051EBE7 /* MoleculeListCellProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D296E1412295EBBA0051EBE7 /* MoleculeDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D296E143229729C30051EBE7 /* MoleculeMappingObject+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */; }; D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */; }; D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770EE21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m */; }; @@ -173,10 +178,12 @@ 0105618A224BBE7700E1557D /* FormValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidator.swift; sourceTree = ""; }; 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; + 016A1070228122180009D605 /* SwitchLineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchLineItem.swift; sourceTree = ""; }; 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = ""; }; 0198F79E225679870066C936 /* FormValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidationProtocol.swift; sourceTree = ""; }; 0198F7A02256A80A0066C936 /* MFRadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFRadioButton.h; sourceTree = ""; }; 0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = ""; }; + 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -196,6 +203,9 @@ D282AACA2243C61700C46919 /* ButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonView.swift; sourceTree = ""; }; D28B4F8821FF967C00712C7A /* MVMCoreUIObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIObject.h; sourceTree = ""; }; D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIObject.m; sourceTree = ""; }; + D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeListCellProtocol.h; sourceTree = ""; }; + D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeDelegateProtocol.h; sourceTree = ""; }; + D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MoleculeMappingObject+Extension.swift"; sourceTree = ""; }; D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = ""; }; D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsView.h; sourceTree = ""; }; D29770EE21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsAndBottomButtonsTableViewController.m; sourceTree = ""; }; @@ -415,6 +425,7 @@ 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */, D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */, D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */, + D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */, D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */, ); path = Templates; @@ -446,6 +457,8 @@ D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */, D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */, D282AACA2243C61700C46919 /* ButtonView.swift */, + 016A1070228122180009D605 /* SwitchLineItem.swift */, + 01CA51B4229716F60071A6EE /* Switch.swift */, D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */, D2A514662213885800345BFB /* StandardHeaderView.swift */, D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */, @@ -657,8 +670,10 @@ D29DF27421E79E81003B2FB9 /* MVMCoreUILoggingHandler.m */, D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */, D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */, + D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */, D2A514562211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.h */, D2A514572211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m */, + D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */, ); path = OtherHandlers; sourceTree = ""; @@ -779,6 +794,7 @@ D29DF12D21E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h in Headers */, D29DF24E21E6A177003B2FB9 /* MFDigitTextField.h in Headers */, D29770F321F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h in Headers */, + D296E1412295EBBA0051EBE7 /* MoleculeDelegateProtocol.h in Headers */, D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */, D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */, D29DF17421E69E1F003B2FB9 /* MFCustomButton.h in Headers */, @@ -787,6 +803,7 @@ D29DF2A121E7AF4E003B2FB9 /* MVMCoreUIUtility.h in Headers */, D29DF17621E69E1F003B2FB9 /* PrimaryButton.h in Headers */, D29DF2C821E7BFC1003B2FB9 /* MFSizeObject.h in Headers */, + D296E13C229598BF0051EBE7 /* MoleculeListCellProtocol.h in Headers */, D29DF32021ED0CBA003B2FB9 /* LabelView.h in Headers */, D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */, D29DF2E121E9240B003B2FB9 /* MVMCoreUIPanelProtocol.h in Headers */, @@ -921,10 +938,12 @@ D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */, D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */, + D296E143229729C30051EBE7 /* MoleculeMappingObject+Extension.swift in Sources */, 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */, D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */, D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, + 016A1071228122180009D605 /* SwitchLineItem.swift in Sources */, D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, @@ -944,6 +963,7 @@ 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 */, diff --git a/MVMCoreUI/Atoms/Buttons/CaretButton.swift b/MVMCoreUI/Atoms/Buttons/CaretButton.swift index 0176b147..4503a1f3 100644 --- a/MVMCoreUI/Atoms/Buttons/CaretButton.swift +++ b/MVMCoreUI/Atoms/Buttons/CaretButton.swift @@ -9,6 +9,7 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol { + //------------------------------------------------------ // MARK: - Constants //------------------------------------------------------ @@ -51,6 +52,9 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol { changeCaretColor() } + public func updateView(_ size: CGFloat) { + } + //------------------------------------------------------ // MARK: - Functions //------------------------------------------------------ @@ -110,7 +114,7 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol { setTitleColor(disabledColor, for: .disabled) } - @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { setWithActionMap(json, delegateObject: delegateObject, additionalData: additionalData) guard let dictionary = json else { return } diff --git a/MVMCoreUI/Atoms/Buttons/MFTextButton.m b/MVMCoreUI/Atoms/Buttons/MFTextButton.m index d78df33d..4c513ef9 100644 --- a/MVMCoreUI/Atoms/Buttons/MFTextButton.m +++ b/MVMCoreUI/Atoms/Buttons/MFTextButton.m @@ -128,7 +128,7 @@ #pragma mark - MVMCoreUIMoleculeViewProtocol -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { NSString *color = [json string:KeyTextColor]; if (color) { [self setTitleColor:[UIColor mfGetColorForHex:color] forState:UIControlStateNormal]; diff --git a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m index 2085b5c8..b2fe18d2 100644 --- a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m +++ b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m @@ -648,10 +648,8 @@ [self setAsStandardCustom]; } -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { - if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) { - [FormValidator setupValidationWithMolecule:self delegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol]; - } +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { + [FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol]; self.primaryButtonType = PrimaryButtonTypeCustom; NSString *color = [json string:@"fillColor"]; diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField.m b/MVMCoreUI/Atoms/TextFields/MFTextField.m index 52580f46..55d6f8e6 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField.m +++ b/MVMCoreUI/Atoms/TextFields/MFTextField.m @@ -559,14 +559,14 @@ self.isMolecule = YES; } -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) { - [FormValidator setupValidationWithMolecule:self delegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol]; - FormValidator *formValidator = [FormValidator getFormValidatorForDelegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol]; + [FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol]; + FormValidator *formValidator = [FormValidator getFormValidatorForDelegate:delegateObject.formValidationProtocol]; [self setWithMap:json]; self.mfTextFieldDelegate = formValidator; - self.uiTextFieldDelegate = ((MVMCoreUIDelegateObject *)delegateObject).uiTextFieldDelegate; + self.uiTextFieldDelegate = delegateObject.uiTextFieldDelegate; [MVMCoreUICommonViewsUtility addDismissToolbar:self.textField delegate:self.uiTextFieldDelegate]; } } diff --git a/MVMCoreUI/Atoms/Views/CaretView.swift b/MVMCoreUI/Atoms/Views/CaretView.swift index 56566287..f5ee49c3 100644 --- a/MVMCoreUI/Atoms/Views/CaretView.swift +++ b/MVMCoreUI/Atoms/Views/CaretView.swift @@ -103,7 +103,7 @@ open class CaretView: MFView { defaultState() } - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + 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 dictionary = json else { return } diff --git a/MVMCoreUI/Atoms/Views/DashLine.swift b/MVMCoreUI/Atoms/Views/DashLine.swift index 82c05b27..e9ca4a78 100644 --- a/MVMCoreUI/Atoms/Views/DashLine.swift +++ b/MVMCoreUI/Atoms/Views/DashLine.swift @@ -68,7 +68,7 @@ open class DashLine: MFView { isHidden = false } - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + 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 diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 0cd77ee0..6302ed90 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -295,7 +295,7 @@ import MVMCore // MARK: - Atomization //------------------------------------------------------ - @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { Label.setUILabel(self, withJSON: json, delegate: delegateObject, additionalData: additionalData) originalAttributedString = attributedText } diff --git a/MVMCoreUI/Atoms/Views/LabelView.m b/MVMCoreUI/Atoms/Views/LabelView.m index 56091d24..e0817374 100644 --- a/MVMCoreUI/Atoms/Views/LabelView.m +++ b/MVMCoreUI/Atoms/Views/LabelView.m @@ -73,7 +73,7 @@ } } -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; [self.label setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; } diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 502c766a..76693a6b 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -734,7 +734,7 @@ extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol { } - @objc open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + @objc open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { // Configure class properties with JSON values guard let dictionary = json else { return } diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index 69ef1b6f..2a72481e 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -197,13 +197,12 @@ import UIKit if let imageName = json?.optionalStringForKey("image"), shouldLoadImage(withName: imageName, width: width) { imageView.image = nil imageView.animatedImage = nil - loadImage(withName: imageName, format: json?.optionalStringForKey("imageFormat"), width: NSNumber(value: Double(width)), height: nil) loadImage(withName: imageName, format: json?.optionalStringForKey("imageFormat"), width: NSNumber(value: Double(width)), height: nil, customFallbackImage: json?.optionalStringForKey("fallbackImage")) } } // MARK: - MVMCoreUIMoleculeViewProtocol functions - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { backgroundColor = UIColor.mfGet(forHex: backgroundColorString) diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index b22a5674..029c6ce2 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -44,7 +44,7 @@ #pragma mark - MVMCoreUIMoleculeViewProtocol -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { self.json = json; } diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m b/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m index cb6f7eaf..cf608538 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m @@ -58,7 +58,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0; return UIStackViewAlignmentLeading; } -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) { [FormValidator setupValidationWithMolecule:self delegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol]; diff --git a/MVMCoreUI/Atoms/Views/SeparatorView.m b/MVMCoreUI/Atoms/Views/SeparatorView.m index 95fe8bb8..50e59758 100644 --- a/MVMCoreUI/Atoms/Views/SeparatorView.m +++ b/MVMCoreUI/Atoms/Views/SeparatorView.m @@ -95,17 +95,21 @@ } } -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; if (json) { - self.hidden = NO; NSString *type = [json string:KeyType]; - if ([type isEqualToString:@"standard"]) { - [self setSize:1]; - } else if ([type isEqualToString:@"medium"]) { - [self setSize:2]; - } else if ([type isEqualToString:@"heavy"]) { - [self setSize:4]; + if ([type isEqualToString:@"none"]) { + self.hidden = YES; + } else { + self.hidden = NO; + if ([type isEqualToString:@"medium"]) { + [self setAsMedium]; + } else if ([type isEqualToString:@"heavy"]) { + [self setAsHeavy]; + } else { + [self setAsLight]; + } } NSString *backgroundColor = [json string:KeyBackgroundColor]; if (backgroundColor) { diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index c1e3e5ff..d433388c 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -151,7 +151,7 @@ self.updateViewHorizontalDefaults = YES; } -- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; if (self.molecule) { [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; diff --git a/MVMCoreUI/BaseControllers/MFViewController.h b/MVMCoreUI/BaseControllers/MFViewController.h index 8c1d5766..f1b87dc6 100644 --- a/MVMCoreUI/BaseControllers/MFViewController.h +++ b/MVMCoreUI/BaseControllers/MFViewController.h @@ -27,13 +27,14 @@ #import #import #import +#import @class MainMenuViewController; @class MVMCoreUITabBarPageControlViewController; @class MVMAnimationManager; @class DelegateObject; -@interface MFViewController : UIViewController +@interface MFViewController : UIViewController // Stores the load object that this screen was loaded with. @property (nullable, strong, nonatomic) MVMCoreLoadObject *loadObject; diff --git a/MVMCoreUI/BaseControllers/MFViewController.m b/MVMCoreUI/BaseControllers/MFViewController.m index b6f71412..6aff745a 100644 --- a/MVMCoreUI/BaseControllers/MFViewController.m +++ b/MVMCoreUI/BaseControllers/MFViewController.m @@ -786,6 +786,15 @@ } } +#pragma mark - MoleculeDelegateProtocol + +- (NSDictionary *)getModuleWithName:(NSString *)name { + if (!name) { + return nil; + } + return [self.loadObject.modulesJSON dict:name]; +} + #pragma mark - adobe analytics - (nullable NSArray *)additionalActionsToTrackWithMainActionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData { diff --git a/MVMCoreUI/MVMCoreUI.h b/MVMCoreUI/MVMCoreUI.h index 8b4e24bd..b5ccd8e1 100644 --- a/MVMCoreUI/MVMCoreUI.h +++ b/MVMCoreUI/MVMCoreUI.h @@ -20,6 +20,8 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[]; #import #import #import +#import +#import #import #pragma mark - TopAlert diff --git a/MVMCoreUI/Molecules/ButtonView.swift b/MVMCoreUI/Molecules/ButtonView.swift index c23f1aa9..d03a2e72 100644 --- a/MVMCoreUI/Molecules/ButtonView.swift +++ b/MVMCoreUI/Molecules/ButtonView.swift @@ -33,7 +33,7 @@ import UIKit primaryButton?.isEnabled = enabled } - public init(withJSON json: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) { + public init(withJSON json: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { super.init(frame: .zero) setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } @@ -58,11 +58,15 @@ import UIKit primaryButton?.setAsMolecule() } - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) primaryButton?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?) -> CGFloat { + return 42 + } + // MARK: - Constraining func setupButton() { if let primaryButton = primaryButton, !subviews.contains(primaryButton) { diff --git a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h index 12557967..67e64d24 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h +++ b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h @@ -7,12 +7,13 @@ // #import -@class DelegateObject; +@import MVMCore.MVMCoreViewProtocol; +@class MVMCoreUIDelegateObject; -@protocol MVMCoreUIMoleculeViewProtocol +@protocol MVMCoreUIMoleculeViewProtocol // Sets up the ui based on the json -- (void)setWithJSON:(nullable NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; +- (void)setWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; @optional @@ -26,7 +27,7 @@ - (UIStackViewAlignment)moleculeAlignment; // For the molecule list to load more efficiently. -+ (CGFloat)estimatedHeightForRow; ++ (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json; @end diff --git a/MVMCoreUI/Molecules/MoleculeStackView.swift b/MVMCoreUI/Molecules/MoleculeStackView.swift index ef060718..5f7f8957 100644 --- a/MVMCoreUI/Molecules/MoleculeStackView.swift +++ b/MVMCoreUI/Molecules/MoleculeStackView.swift @@ -18,12 +18,12 @@ public class MoleculeStackView: MFView { super.init(frame: frame) } - public init(withJSON json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) { + public init(withJSON json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { super.init(frame: CGRect.zero) setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } - public convenience init(withJSON json: [AnyHashable: Any]?, delegateObject: DelegateObject?, spacingBlock: ((Any) -> UIEdgeInsets)?) { + public convenience init(withJSON json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, spacingBlock: ((Any) -> UIEdgeInsets)?) { self.init(withJSON: json, delegateObject: delegateObject, additionalData: nil) self.spacingBlock = spacingBlock } @@ -51,7 +51,7 @@ public class MoleculeStackView: MFView { } // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else { return @@ -60,7 +60,7 @@ public class MoleculeStackView: MFView { // Create the molecules and set the json. var moleculesArray = [] as [UIView] for moleculeJSON in molecules { - if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject) { + if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { moleculesArray.append(molecule) } } diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index 1df0e67d..e0053437 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -8,8 +8,10 @@ import UIKit -@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol { +@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { + open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + open var json: [AnyHashable: Any]? // For the accessory view convenience. public var caretView: CaretView? @@ -50,9 +52,7 @@ import UIKit bottomSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left) } - if let molecule = molecule as? MVMCoreViewProtocol { - molecule.updateView(size) - } + molecule?.updateView(size) if let _ = accessoryView, let caretView = caretView, let widthObject = caretViewWidthSizeObject, let heightObject = caretViewHeightSizeObject { caretView.frame = CGRect(x: 0, y: 0, width: widthObject.getValueBased(onSize: size), height: heightObject.getValueBased(onSize: size)) } @@ -67,23 +67,46 @@ import UIKit } // MARK: - MVMCoreUIMoleculeViewProtocol - public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) { - guard let json = json else { + public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + self.json = json; + guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return } if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: json, delegateObject: delegateObject) { + if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { contentView.addSubview(moleculeView) NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: moleculeView.needsToBeConstrained?() ?? false).values)) molecule = moleculeView } } else { - molecule?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) } backgroundColor = molecule?.backgroundColor + + // 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 + } + + // override the separator + if let separator = json.optionalDictionaryForKey("separator") { + addSeparatorsIfNeeded() + bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) + } } - // MARK: - Convenience + public static func estimatedHeight(forRow json: [AnyHashable : Any]?) -> CGFloat { + guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), + let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON, delegateObject: nil), + let estimatedHeightFor = theClass.estimatedHeight else { + return 0 + } + return estimatedHeightFor(moleculeJSON) + } + + // MARK: - Arrow /// Adds the standard mvm style caret to the accessory view public func addCaretViewAccessory() { guard accessoryView == nil else { @@ -98,6 +121,34 @@ import UIKit accessoryView = caretView } + // MARK: - MoleculeListCellProtocol + public static func moleculeName(_ molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + return molecule?.optionalDictionaryForKey(KeyMolecule)?.optionalStringForKey(KeyMoleculeName) + } + + /// 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) { + addSeparatorsIfNeeded() + if let json = json { + topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) { + setSeparatorFrequency(separatorFrequency, indexPath: indexPath) + } + } else { + topSeparatorView?.hide() + bottomSeparatorView?.setAsLight() + setSeparatorFrequency(MoleculeTableViewCell.SeparatorFrequency.AllExceptTop, indexPath: indexPath) + } + } + + public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + if let actionMap = json?.optionalDictionaryForKey("actionMap") { + MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) + } + } + + // MARK: - Separator func addSeparatorsIfNeeded() { if topSeparatorView == nil { topSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionTop) @@ -109,19 +160,6 @@ import UIKit } } - /// For when the separator between cells shows using json and frequency. - public func setSeparatorWithJSON(_ json: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?, indexPath: IndexPath) { - guard let json = json else { - return - } - addSeparatorsIfNeeded() - topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) { - setSeparatorFrequency(separatorFrequency, indexPath: indexPath) - } - } - /// For when the separator between cells shows. public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) { switch separatorFrequency { diff --git a/MVMCoreUI/Molecules/StandardFooterView.swift b/MVMCoreUI/Molecules/StandardFooterView.swift index 06d39c47..5c4aa688 100644 --- a/MVMCoreUI/Molecules/StandardFooterView.swift +++ b/MVMCoreUI/Molecules/StandardFooterView.swift @@ -93,7 +93,7 @@ public class StandardFooterView: ViewConstrainingView { layoutIfNeeded() } - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) if let colorString = json?.optionalStringForKey(KeyBackgroundColor) { backgroundColor = .mfGet(forHex: colorString) diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index 58aa727c..308341fa 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -110,7 +110,7 @@ public class StandardHeaderView: ViewConstrainingView { separatorView?.rightPin?.constant = constant } - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) if let colorString = json?.optionalStringForKey(KeyBackgroundColor) { backgroundColor = .mfGet(forHex: colorString) diff --git a/MVMCoreUI/Molecules/Switch.swift b/MVMCoreUI/Molecules/Switch.swift new file mode 100644 index 00000000..b97496a3 --- /dev/null +++ b/MVMCoreUI/Molecules/Switch.swift @@ -0,0 +1,87 @@ +// +// Switch.swift +// MVMCoreUI +// +// Created by Priya on 5/23/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class Switch: ViewConstrainingView, FormValidationProtocol{ + public var mvmSwitch = MVMCoreUISwitch() + var isRequired = false + var delegateObject: DelegateObject? + + @objc func switchChanged() { + let delegate = delegateObject as? MVMCoreUIDelegateObject + if let delegate = delegate { + let formValidator = delegate.formValidationProtocol?.formValidatorModel?() + formValidator?.enableByValidation() + } + } + + open override func setupView() { + super.setupView() + mvmSwitch.addTarget(self, action: #selector(Switch.switchChanged), for: .valueChanged) + self.clipsToBounds = true + addSubview(mvmSwitch) + mvmSwitch.translatesAutoresizingMaskIntoConstraints = false + setupContainerConstraints() + } + + public override func updateView(_ size: CGFloat) { + super.updateView(size) + mvmSwitch.updateView(size) + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + isRequired = json?[KeyRequired] as? Bool ?? false + self.delegateObject = delegateObject + if let delegateObject = delegateObject { + FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol) + } + if let onColorString = json?.optionalStringForKey("onTintColor") { + mvmSwitch.onTintColor = .mfGet(forHex: onColorString) + } + if let offColorString = json?.optionalStringForKey("offTintColor") { + mvmSwitch.offTintColor = .mfGet(forHex: offColorString) + } + if let onKnobColorString = json?.optionalStringForKey("onKnobTintColor") { + mvmSwitch.onKnobTintColor = .mfGet(forHex: onKnobColorString) + } + if let offKnobColorString = json?.optionalStringForKey("offKnobTintColor") { + mvmSwitch.offKnobTintColor = .mfGet(forHex: offKnobColorString) + } + mvmSwitch.setState(json?.optionalBoolForKey("state") ?? false, animated: true) + } + + func setupContainerConstraints() { + mvmSwitch.topAnchor.constraint(equalTo: topAnchor).isActive = true + mvmSwitch.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + mvmSwitch.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + mvmSwitch.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true + } + + public func isValidField() -> Bool { + return (isRequired == false) ? true : mvmSwitch.isOn + } + + public func formFieldName() -> String? { + return json?.optionalStringForKey(KeyFieldKey) + } + + public func formFieldValue() -> Any? { + return mvmSwitch.isOn + } + + public override func needsToBeConstrained() -> Bool { + return true + } + + public override func moleculeAlignment() -> UIStackView.Alignment { + return UIStackView.Alignment.leading + } +} + diff --git a/MVMCoreUI/Molecules/SwitchLineItem.swift b/MVMCoreUI/Molecules/SwitchLineItem.swift new file mode 100644 index 00000000..665de248 --- /dev/null +++ b/MVMCoreUI/Molecules/SwitchLineItem.swift @@ -0,0 +1,121 @@ +// +// SwitchLineItem.swift +// MVMCoreUI +// +// Created by Priya on 5/6/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class SwitchLineItem: ViewConstrainingView, FormValidationProtocol{ + public var mvmSwitch = Switch() + public var label = Label() + public var leftContainerView = UIView() + public var mfTextButton = MFTextButton(nil, constrainHeight: true, forWidth: 0) + var isRequired = false + var delegateObject: DelegateObject? + + @objc func switchChanged() { + let delegate = delegateObject as? MVMCoreUIDelegateObject + if let delegate = delegate { + let formValidator = delegate.formValidationProtocol?.formValidatorModel?() + formValidator?.enableByValidation() + } + } + + open override func setupView() { + super.setupView() + leftContainerView.addSubview(label) + leftContainerView.addSubview(mfTextButton) + addSubview(leftContainerView) + addSubview(mvmSwitch) + + leftContainerView.translatesAutoresizingMaskIntoConstraints = false + mvmSwitch.translatesAutoresizingMaskIntoConstraints = false + mfTextButton.translatesAutoresizingMaskIntoConstraints = false + label.translatesAutoresizingMaskIntoConstraints = false + setupContainerConstraints() + } + + public override func updateView(_ size: CGFloat) { + super.updateView(size) + label.updateView(size) + mvmSwitch.updateView(size) + mfTextButton.updateView(size) + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + mvmSwitch.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + label.setWithJSON(json?.optionalDictionaryForKey("label"), delegateObject: delegateObject, additionalData: additionalData) + mfTextButton.setWithJSON(json?.optionalDictionaryForKey("textButton"), delegateObject: delegateObject, additionalData: additionalData) + if (label.text?.count ?? 0) <= 0 && (mfTextButton.titleLabel?.text?.count ?? 0) <= 0 { + mvmSwitch.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0).isActive = true + } + } + + func setupContainerConstraints() { + leftContainerView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + + var constraint = leftContainerView.topAnchor.constraint(equalTo: topAnchor) + constraint.priority = UILayoutPriority(249) + constraint.isActive = true + + mvmSwitch.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + + constraint = mvmSwitch.topAnchor.constraint(equalTo: topAnchor) + constraint.priority = UILayoutPriority(249) + constraint.isActive = true + + trailingAnchor.constraint(equalTo: mvmSwitch.trailingAnchor).isActive = true + + constraint = bottomAnchor.constraint(equalTo: mvmSwitch.bottomAnchor) + constraint.priority = UILayoutPriority(249) + constraint.isActive = true + + bottomAnchor.constraint(greaterThanOrEqualTo: mvmSwitch.bottomAnchor).isActive = true + + constraint = bottomAnchor.constraint(equalTo: leftContainerView.bottomAnchor) + constraint.isActive = true + + bottomAnchor.constraint(greaterThanOrEqualTo: leftContainerView.bottomAnchor).isActive = true + leftContainerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + + NSLayoutConstraint.constraintPinSubview(leftContainerView, pinCenterX: false, pinCenterY: true) + constraint = mvmSwitch.leadingAnchor.constraint(greaterThanOrEqualTo: leftContainerView.trailingAnchor) + constraint.priority = UILayoutPriority(999) + constraint.isActive = true + NSLayoutConstraint.constraintPinSubview(mvmSwitch, pinCenterX: false, pinCenterY: true) + + leftContainerView.topAnchor.constraint(equalTo: label.topAnchor).isActive = true + leftContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: label.trailingAnchor).isActive = true + + constraint = leftContainerView.trailingAnchor.constraint(equalTo: label.trailingAnchor) + constraint.priority = UILayoutPriority(249) + constraint.isActive = true + + leftContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: mfTextButton.trailingAnchor).isActive = true + + constraint = leftContainerView.trailingAnchor.constraint(equalTo: mfTextButton.trailingAnchor) + constraint.priority = UILayoutPriority(249) + constraint.isActive = true + + leftContainerView.bottomAnchor.constraint(equalTo: mfTextButton.bottomAnchor).isActive = true + mfTextButton.leadingAnchor.constraint(equalTo: leftContainerView.leadingAnchor).isActive = true + label.leadingAnchor.constraint(equalTo: leftContainerView.leadingAnchor).isActive = true + mfTextButton.topAnchor.constraint(equalTo: label.bottomAnchor).isActive = true + leftContainerView.setContentHuggingPriority(.defaultHigh, for: .horizontal) + mvmSwitch.setContentHuggingPriority(.defaultLow, for: .horizontal) + } + + public override func needsToBeConstrained() -> Bool { + return true + } + + public override func moleculeAlignment() -> UIStackView.Alignment { + return UIStackView.Alignment.leading + } +} + + diff --git a/MVMCoreUI/Molecules/TwoButtonView.swift b/MVMCoreUI/Molecules/TwoButtonView.swift index 66b7210a..ca3c8215 100644 --- a/MVMCoreUI/Molecules/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/TwoButtonView.swift @@ -39,7 +39,7 @@ import UIKit } // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { backgroundColor = UIColor.mfGet(forHex: backgroundColorString) @@ -142,7 +142,7 @@ import UIKit } } - open func set(primaryButtonJSON: [AnyHashable: Any]?, secondaryButtonJSON: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + open func set(primaryButtonJSON: [AnyHashable: Any]?, secondaryButtonJSON: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { setupUI(withPrimaryButtonMap: primaryButtonJSON, secondaryButtonMap: secondaryButtonJSON, legacy: false) setDefaultCustom() primaryButton?.setWithJSON(primaryButtonJSON, delegateObject: delegateObject, additionalData: additionalData) diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift index 92744a8c..c0c8211f 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift @@ -12,11 +12,17 @@ open class MVMCoreUIDelegateObject: DelegateObject { public weak var formValidationProtocol: FormValidationProtocol? public weak var buttonDelegate: ButtonDelegateProtocol? public weak var uiTextFieldDelegate: UITextFieldDelegate? + public weak var moleculeDelegate: MoleculeDelegateProtocol? open override func setAll(withDelegate delegate: Any) { super.setAll(withDelegate: delegate) formValidationProtocol = delegate as? FormValidationProtocol buttonDelegate = delegate as? ButtonDelegateProtocol uiTextFieldDelegate = delegate as? UITextFieldDelegate + moleculeDelegate = delegate as? MoleculeDelegateProtocol + } + + class func delegateObject(from controller: MVMCoreViewControllerProtocol?) -> MVMCoreUIDelegateObject? { + return controller?.delegateObject?() as? MVMCoreUIDelegateObject } } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h index 43a113c9..4e7dd8db 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h @@ -8,21 +8,35 @@ #import #import -@class DelegateObject; +@class MVMCoreUIDelegateObject; +@class MVMCoreLoadObject; +@class MVMCoreErrorObject; @interface MVMCoreUIMoleculeMappingObject : NSObject -// Maps molecule name to class. -@property (nullable, strong, nonatomic) NSMutableDictionary *moleculeMapping; +/// Maps molecule name to class. +@property (nonnull, strong, nonatomic) NSMutableDictionary *moleculeMapping; -// Returns the shared instance +/// Returns the shared instance + (nullable instancetype)sharedMappingObject; -// Returns the molecule for the given name. -- (nullable UIView *)getMoleculeForName:(nonnull NSString *)name; -- (nullable UIView *)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject; +/// Returns the molecule class. +- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject; -// Similar to above but also checks if the molecule needs to be constrained for a stack. -- (nullable UIView *)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject; +#pragma mark - Molecule Creation + +/// Creates the molecule for the given name. +- (nullable UIView *)createMoleculeForName:(nonnull NSString *)name; + +/// Creates the molecule for the molecule json. Takes into account moduleMolecule as well. +- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject; + +/// Creates the molecule for the molecule json. Takes into account moduleMolecule as well. Also checks if the molecule needs to be constrained for a stack/list style situation. +- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded; + +#pragma mark - ModuleMolecule Helpers + +/// If the molecule is a module molecule, will get the map for the molecule to load from a module. Otherwise nil. ++ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error; @end diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index d6e7d9f2..3b84ad78 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -9,6 +9,7 @@ #import "MVMCoreUIMoleculeMappingObject.h" @import MVMCore.MVMCoreActionUtility; @import MVMCore.NSDictionary_MFConvenience; +@import MVMCore.MVMCoreLoadObject; #import "MVMCoreUIObject.h" #import #import "MFTextField.h" @@ -32,9 +33,12 @@ @"standardFooter": StandardFooterView.class, @"caretView": CaretView.class, @"caretButton": CaretButton.class, - @"textField" : MFTextField.class, + @"textField": MFTextField.class, + @"checkbox": MVMCoreUICheckBox.class, @"radioButton": RadioButton.class, - @"checkbox" : MVMCoreUICheckBox.class + @"listItem": MoleculeTableViewCell.class, + @"switchLineItem": SwitchLineItem.class, + @"switch": Switch.class } mutableCopy]; }); return mapping; @@ -45,7 +49,18 @@ return [MVMCoreActionUtility initializerClassCheck:[MVMCoreUIObject sharedInstance].moleculeMap classToVerify:self]; } -- (nullable UIView *)getMoleculeForName:(nonnull NSString *)name { +- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject { + NSDictionary *moleculeJSON = [MVMCoreUIMoleculeMappingObject getMoleculeMapForModuleMolecule:json delegateObject:delegateObject error:nil] ?: json; + NSString *moleculeName = [moleculeJSON string:KeyMoleculeName]; + if (moleculeName) { + return [self.moleculeMapping objectForKey:moleculeName]; + } + return nil; +} + +#pragma mark - Molecule Creation + +- (nullable UIView *)createMoleculeForName:(nonnull NSString *)name { Class class = [self.moleculeMapping objectForKey:name]; if (!class) { return nil; @@ -57,28 +72,38 @@ return molecule; } -- (nullable UIView *)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject { - NSString *moleculeName = [json string:KeyMoleculeName]; +- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject { + return [self createMoleculeForJSON:json delegateObject:delegateObject constrainIfNeeded:NO]; +} + +- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded { + NSDictionary *moleculeJSON = [MVMCoreUIMoleculeMappingObject getMoleculeMapForModuleMolecule:json delegateObject:delegateObject error:nil] ?: json; + NSString *moleculeName = [moleculeJSON string:KeyMoleculeName]; if (!moleculeName) { return nil; } - UIView *molecule = [self getMoleculeForName:moleculeName]; - [molecule setWithJSON:json delegateObject:delegateObject additionalData:nil]; + UIView *molecule = [self createMoleculeForName:moleculeName]; + if (constrainIfNeeded && [molecule respondsToSelector:@selector(needsToBeConstrained)] && [molecule needsToBeConstrained]) { + molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[molecule respondsToSelector:@selector(moleculeAlignment)] ? [molecule moleculeAlignment] : UIStackViewAlignmentFill]; + } + [molecule setWithJSON:moleculeJSON delegateObject:delegateObject additionalData:nil]; return molecule; } +#pragma mark - ModuleMolecule Helpers -- (nullable UIView *)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject { - NSString *moleculeName = [json string:KeyMoleculeName]; - if (!moleculeName) { ++ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error { + NSString *moleculeName = [moduleMolecule string:KeyMoleculeName]; + if ([moleculeName isEqualToString:@"moduleMolecule"]) { + NSString *moduleName = [moduleMolecule string:@"moduleName"]; + NSDictionary *module = moduleName ? [delegateObject.moleculeDelegate getModuleWithName:moduleName] : nil; + if (!module && error) { + *error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeModuleMolecule domain:ErrorDomainNative location:NSStringFromClass(self)]; + } + return module; + } else { return nil; } - UIView *molecule = [self getMoleculeForName:moleculeName]; - if ([molecule respondsToSelector:@selector(needsToBeConstrained)] && [molecule needsToBeConstrained]) { - molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[molecule respondsToSelector:@selector(moleculeAlignment)] ? [molecule moleculeAlignment] : UIStackViewAlignmentFill]; - } - [molecule setWithJSON:json delegateObject:delegateObject additionalData:nil]; - return molecule; } @end diff --git a/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h new file mode 100644 index 00000000..0d027386 --- /dev/null +++ b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h @@ -0,0 +1,15 @@ +// +// MoleculeDelegateProtocol.h +// MVMCoreUI +// +// Created by Scott Pfeil on 5/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// +#import + +@protocol MoleculeDelegateProtocol + +/// returns a module for the corresponding module name. +- (nullable NSDictionary *)getModuleWithName:(nullable NSString *)name; + +@end diff --git a/MVMCoreUI/OtherHandlers/MoleculeMappingObject+Extension.swift b/MVMCoreUI/OtherHandlers/MoleculeMappingObject+Extension.swift new file mode 100644 index 00000000..3c88a743 --- /dev/null +++ b/MVMCoreUI/OtherHandlers/MoleculeMappingObject+Extension.swift @@ -0,0 +1,47 @@ +// +// MoleculeMappingObject+Extension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 5/23/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public extension MVMCoreUIMoleculeMappingObject { + + /// Gets the molecule, and if it belonged to a moduleMolecule, the module name or error. + static func getMoleculeJSON(for map: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)? { + guard let map = map, let moleculeName = map.optionalStringForKey(KeyMoleculeName) else { + return nil + } + guard moleculeName == "moduleMolecule" else { + // Not a module molecule. + return (map, nil, nil) + } + + guard let moduleName = map.optionalStringForKey("moduleName"), + let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { + guard let error = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) else { + return nil + } + MVMCoreUILoggingHandler.shared()?.addError(toLog: error) + return (nil, nil, error) + } + return (module, moduleName, nil) + } + + /// Gets the molecule, and if it belonged to a moduleMolecule adds the module name or error to the passed lists. + static func getMoleculeJSON(for map: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, moduleNames: inout [String]?, errors: inout [MVMCoreErrorObject]?) -> [AnyHashable: Any]? { + guard let molecule = getMoleculeJSON(for: map, delegateObject: delegateObject) else { + return nil + } + if let moduleName = molecule.moduleName { + moduleNames?.append(moduleName) + } + if let error = molecule.error { + errors?.append(error) + } + return molecule.molecule + } +} diff --git a/MVMCoreUI/Styles/MFStyler.h b/MVMCoreUI/Styles/MFStyler.h index 49f02db0..09299a82 100644 --- a/MVMCoreUI/Styles/MFStyler.h +++ b/MVMCoreUI/Styles/MFStyler.h @@ -157,6 +157,9 @@ B3 -> Legal //75Bd 10pt only for support + (nullable UIFont *)fontForUnreadMessageOnSupport; +//55Rg 16pt for 5G flow ++ (nullable UIFont *)font5GMessage:(BOOL)genericScaling; + // Returns the fonts for these styles allowing to apply a generic scale by device or not. + (nullable UIFont *)fontForBiggerHeadLine:(BOOL)genericScaling; + (nullable UIFont *)fontForPlan:(BOOL)genericScaling; diff --git a/MVMCoreUI/Styles/MFStyler.m b/MVMCoreUI/Styles/MFStyler.m index ca0fcd2e..a1e60db6 100644 --- a/MVMCoreUI/Styles/MFStyler.m +++ b/MVMCoreUI/Styles/MFStyler.m @@ -347,6 +347,15 @@ CGFloat const LabelWithInternalButtonLineSpace = 2; return [MFFonts mfFont75Bd:size]; } ++ (nullable UIFont *)font5GMessage:(BOOL)genericScaling { + CGFloat size = 16; + if (genericScaling) { + size = [self sizeFontGenericForCurrentDevice:size]; + } + return [MFFonts mfFont55Rg:size]; +} + + + (nullable UIFont *)fontForHeadlineAlternative:(BOOL)genericScaling { CGFloat size = 24; if (genericScaling) { diff --git a/MVMCoreUI/Templates/MoleculeListCellProtocol.h b/MVMCoreUI/Templates/MoleculeListCellProtocol.h new file mode 100644 index 00000000..08ca2a37 --- /dev/null +++ b/MVMCoreUI/Templates/MoleculeListCellProtocol.h @@ -0,0 +1,22 @@ +// +// MoleculeListCellProtocol.h +// MVMCoreUI +// +// Created by Scott Pfeil on 5/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// +#import +@class MVMCoreUIDelegateObject; + +@protocol MoleculeListCellProtocol +@optional +/// Can override the molecule name for the given molecule. Otherwise we assume value for key moleculeName. ++ (nullable NSString *)moleculeName:(nullable NSDictionary *)molecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject; + +/// Can set the separator according to what the moleculeList commands. +- (void)setSeparatorWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData indexPath:(nonnull NSIndexPath *)indexPath; + +/// Handle action +- (void)didSelectCellAtIndex:(nonnull NSIndexPath *)indexPath delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; + +@end diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index fe891a93..db69218b 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -9,28 +9,33 @@ import UIKit open class MoleculeListTemplate: ThreeLayerTableViewController { + var molecules: [(molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)]? - open override func registerWithTable() { - super.registerWithTable() - guard let molecules = loadObject?.pageJSON?.arrayForKey(KeyMolecules) else { - return + open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { + var shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error) + guard shouldFinish else { + return shouldFinish } - for case let molecule as Dictionary in molecules { - if let moleculeName = molecule.optionalStringForKey(KeyMoleculeName) { - tableView?.register(MoleculeTableViewCell.self, forCellReuseIdentifier: moleculeName) - } + + if let firstError = setup()?.first { + // Don't continue if there was an error loading needed modules. + error.pointee = firstError + shouldFinish = false } + return shouldFinish } open override func viewForTop() -> UIView { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else { + guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return super.viewForTop() } return molecule } override open func viewForBottom() -> UIView { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else { + guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return viewForBottom() } return molecule @@ -38,31 +43,142 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { open override func newDataBuildScreen() { super.newDataBuildScreen() + _ = setupMoleculeList() registerWithTable() } - open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - if let moleculeName = loadObject?.pageJSON?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecules,indexPath.row,KeyMoleculeName]), let theClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping?[moleculeName] as? MVMCoreUIMoleculeViewProtocol.Type, - let estimatedHeightForRow = theClass.estimatedHeightForRow { - return estimatedHeightForRow() + // MARK: - table + open override func registerWithTable() { + super.registerWithTable() + guard let molecules = molecules else { + return } - return 0 + for molecule in molecules { + if let moleculeInfo = getMoleculeInfo(with: molecule), let moleculeToRegister = moleculeInfo.name { + tableView?.register(moleculeInfo.class, forCellReuseIdentifier: moleculeToRegister) + } + } + } + + open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + guard let molecule = molecules?[indexPath.row], + let moleculeInfo = getMoleculeInfo(with: molecule), + let estimatedHeight = moleculeInfo.class.estimatedHeight else { + return 0 + } + return estimatedHeight(molecule.molecule) } open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return loadObject?.pageJSON?.arrayForKey(KeyMolecules).count ?? 0 + return molecules?.count ?? 0 } open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let molecule = loadObject?.pageJSON?.optionalDictionaryWithChainOfKeysOrIndexes([KeyMolecules,indexPath.row]), - let moleculeName = molecule.optionalStringForKey(KeyMoleculeName), - let cell = tableView.dequeueReusableCell(withIdentifier: moleculeName) as? MoleculeTableViewCell else { + guard let molecule = molecules?[indexPath.row], + let moleculeInfo = getMoleculeInfo(with: molecule), + let moleculeName = moleculeInfo.name, + let cell = tableView.dequeueReusableCell(withIdentifier: moleculeName) else { return UITableViewCell() } - let delegate = delegateObject() - cell.setWithJSON(molecule, delegateObject: delegate, additionalData: nil) - cell.setSeparatorWithJSON(loadObject?.pageJSON?.optionalDictionaryForKey("separator"), delegateObject: delegate, additionalData: nil, indexPath: indexPath) - cell.updateView(tableView.bounds.width) + let delegate = delegateObject() as? MVMCoreUIDelegateObject + if let protocolCell = cell as? MoleculeListCellProtocol { + protocolCell.setSeparatorWithJSON?(loadObject?.pageJSON?.optionalDictionaryForKey("separator"), delegateObject: delegate, additionalData: nil, indexPath: indexPath) + } + if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol { + protocolCell.setWithJSON(molecule.molecule, delegateObject: delegate, additionalData: nil) + protocolCell.updateView(tableView.bounds.width) + } return cell } + + open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if let cell = tableView.cellForRow(at: indexPath) as? MoleculeListCellProtocol { + cell.didSelectCell?(atIndex: indexPath, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) + } + } + + // MARK: - cache handling + open override func pageTypesToListenFor() -> [Any]? { + guard let pageType = self.pageType else { + return super.pageTypesToListenFor() + } + return [pageType] + } + + open override func modulesToListenFor() -> [Any]? { + // Get all of the molecules that need modules. + return modulesNeeded() + } + + // MARK: - Module Molecule Handling + /// Returns the (name, class) of the molecule for the given map. + func getMoleculeInfo(with molecule: (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)) -> (name: String?, class: AnyClass)? { + guard let map = molecule.molecule, let moleculeName = map.optionalStringForKey(KeyMoleculeName), let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass else { + return nil + } + if let moleculeClass = moleculeClass as? MoleculeListCellProtocol.Type, let moleculeNameFunc = moleculeClass.moleculeName { + return (moleculeNameFunc(map, delegateObject() as? MVMCoreUIDelegateObject), moleculeClass) + } else { + return (moleculeName, moleculeClass) + } + } + + /// Sets up the molecule list and ensures no errors loading all content. + func setupMoleculeList() -> [MVMCoreErrorObject]? { + var errors: [MVMCoreErrorObject] = [] + let delegate = delegateObject() as? MVMCoreUIDelegateObject + var moleculeList: [(molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)] = [] + if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { + for molecule in molecules { + if let object = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: molecule, delegateObject: delegate) { + if let error = object.error { + errors.append(error) + } else { + moleculeList.append(object) + } + } + } + } + molecules = moleculeList + return errors.count > 0 ? errors : nil + } + + /// Sets up the header, footer, molecule list and ensures no errors loading all content. + func setup() -> [MVMCoreErrorObject]? { + var errors: [MVMCoreErrorObject] = [] + let delegate = delegateObject() as? MVMCoreUIDelegateObject + MoleculeListTemplate.addToErrorList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate), errors: &errors) + MoleculeListTemplate.addToErrorList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate), errors: &errors) + if let newErrors = setupMoleculeList() { + errors.append(contentsOf: newErrors) + } + return errors.count > 0 ? errors : nil + } + + static func addToErrorList(with moleculeObject: (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)?, errors: inout [MVMCoreErrorObject]) { + if let error = moleculeObject?.error { + errors.append(error) + } + } + + static func addToModuleList(with moleculeObject: (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)?, moduleNames: inout [String]) { + if let moduleName = moleculeObject?.moduleName { + moduleNames.append(moduleName) + } + } + + /// Gets a list of required modules + func modulesNeeded() -> [String]? { + var modules: [String] = [] + let delegate = delegateObject() as? MVMCoreUIDelegateObject + + MoleculeListTemplate.addToModuleList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate), moduleNames: &modules) + MoleculeListTemplate.addToModuleList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate), moduleNames: &modules) + if let molecules = molecules { + for molecule in molecules { + MoleculeListTemplate.addToModuleList(with: molecule, moduleNames: &modules) + } + } + return (modules.count > 0 ? modules : nil) + } } diff --git a/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift b/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift index b359ecf5..af5af39c 100644 --- a/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift @@ -8,27 +8,8 @@ import UIKit -public class MoleculeStackCenteredTemplate: ThreeLayerViewController { - - public override func viewForMiddle() -> UIView? { - let molecule = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") - let moleculeStack = MoleculeStackView(withJSON: molecule, delegateObject: delegateObject(), additionalData: nil) - return moleculeStack - } - - public override func viewForTop() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else { - return nil - } - return molecule - } - - override public func viewForBottom() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else { - return nil - } - return molecule +public class MoleculeStackCenteredTemplate: MoleculeStackTemplate { + public override func spaceBetweenTopAndMiddle() -> CGFloat? { + return nil } } diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index 51b3ed7f..3f5e04da 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -10,13 +10,22 @@ import UIKit public class MoleculeStackTemplate: ThreeLayerViewController { + public override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { + var shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error) + if shouldFinish, let firstError = modulesNeeded().errors?.first { + // Don't continue if there was an error loading needed modules. + error.pointee = firstError + shouldFinish = false + } + return shouldFinish + } public override func spaceBetweenTopAndMiddle() -> CGFloat? { return 0 } public override func viewForTop() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else { + guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return nil } return molecule @@ -26,13 +35,42 @@ public class MoleculeStackTemplate: ThreeLayerViewController { guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else { return nil } - return MoleculeStackView(withJSON: moleculeJSON, delegateObject: delegateObject(), additionalData: nil) + return MoleculeStackView(withJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) } override public func viewForBottom() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else { + guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return nil } return molecule } + + // MARK: - cache handling + public override func pageTypesToListenFor() -> [Any]? { + guard let pageType = self.pageType else { + return super.pageTypesToListenFor() + } + return [pageType] + } + + public override func modulesToListenFor() -> [Any]? { + // Get all of the molecules that need modules. + return modulesNeeded().modules + } + + // MARK: - Module Molecule Handling + func modulesNeeded() -> (modules: [String]?, errors: [MVMCoreErrorObject]?) { + var modules: [String]? = [] + var errors: [MVMCoreErrorObject]? = [] + let delegate = delegateObject() as? MVMCoreUIDelegateObject + + let _ = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate, moduleNames: &modules, errors: &errors) + let _ = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate, moduleNames: &modules, errors: &errors) + if let molecules = loadObject?.pageJSON?.optionalArrayForChainOfKeysOrIndexes(["moleculeStack",KeyMolecules]) as? [[AnyHashable: Any]] { + for molecule in molecules { + let _ = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: molecule, delegateObject: delegate, moduleNames: &modules, errors: &errors) + } + } + return (modules?.count ?? 0 > 0 ? modules : nil, errors?.count ?? 0 > 0 ? errors : nil) + } } diff --git a/MVMCoreUI/Utility/MVMCoreUIConstants.h b/MVMCoreUI/Utility/MVMCoreUIConstants.h index 189c2c49..778ede4f 100644 --- a/MVMCoreUI/Utility/MVMCoreUIConstants.h +++ b/MVMCoreUI/Utility/MVMCoreUIConstants.h @@ -15,6 +15,7 @@ extern NSString * const KeyScreenHeading; extern NSString * const KeyMolecules; extern NSString * const KeyMoleculeName; +extern NSString * const KeyMolecule; extern NSString * const KeyDisableButton; @@ -68,3 +69,11 @@ extern BOOL DisableAnimations; // Hand Scroll Key extern NSString * const KeyHandScrollAnimation; extern NSString * const KeyHandScroll; + +#pragma mark - Error Codes + +// Native Error Codes (Add new ones to bottom, don't change order!) +typedef NS_ENUM(NSInteger, CoreUIErrorCode) { + ErrorCodeModuleMolecule = 100, + ErrorCodeListMolecule = 101 +}; diff --git a/MVMCoreUI/Utility/MVMCoreUIConstants.m b/MVMCoreUI/Utility/MVMCoreUIConstants.m index 9735675e..26636266 100644 --- a/MVMCoreUI/Utility/MVMCoreUIConstants.m +++ b/MVMCoreUI/Utility/MVMCoreUIConstants.m @@ -14,6 +14,7 @@ NSString * const KeyScreenHeading = @"screenHeading"; NSString * const KeyMolecules = @"molecules"; NSString * const KeyMoleculeName = @"moleculeName"; +NSString * const KeyMolecule = @"molecule"; NSString * const KeyDisableButton = @"disableAction";