Merge branch 'develop' into feature/standardlistitemwithimage
# Conflicts: # MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m
This commit is contained in:
commit
d79dc3e8ab
@ -40,7 +40,6 @@
|
|||||||
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */; };
|
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, ); }; };
|
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, ); }; };
|
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 */; };
|
|
||||||
D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */; };
|
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, ); }; };
|
D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
@ -50,6 +49,7 @@
|
|||||||
D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */; };
|
D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */; };
|
||||||
D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */; };
|
D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */; };
|
||||||
D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */; };
|
||||||
D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */; };
|
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */; };
|
||||||
D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF11121E6805F003B2FB9 /* UIColor+MFConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF11121E6805F003B2FB9 /* UIColor+MFConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
@ -209,7 +209,6 @@
|
|||||||
D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIObject.m; sourceTree = "<group>"; };
|
D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIObject.m; sourceTree = "<group>"; };
|
||||||
D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeListCellProtocol.h; sourceTree = "<group>"; };
|
D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeListCellProtocol.h; sourceTree = "<group>"; };
|
||||||
D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeDelegateProtocol.h; sourceTree = "<group>"; };
|
D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeDelegateProtocol.h; sourceTree = "<group>"; };
|
||||||
D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MoleculeMappingObject+Extension.swift"; sourceTree = "<group>"; };
|
|
||||||
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewConstrainingProtocol.h; sourceTree = "<group>"; };
|
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewConstrainingProtocol.h; sourceTree = "<group>"; };
|
||||||
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = "<group>"; };
|
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = "<group>"; };
|
||||||
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsView.h; sourceTree = "<group>"; };
|
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsView.h; sourceTree = "<group>"; };
|
||||||
@ -219,6 +218,7 @@
|
|||||||
D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsAndBottomButtonsViewController.m; sourceTree = "<group>"; };
|
D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsAndBottomButtonsViewController.m; sourceTree = "<group>"; };
|
||||||
D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUITextFieldView.m; sourceTree = "<group>"; };
|
D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUITextFieldView.m; sourceTree = "<group>"; };
|
||||||
D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUITextFieldView.h; sourceTree = "<group>"; };
|
D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUITextFieldView.h; sourceTree = "<group>"; };
|
||||||
|
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMolecule.swift; sourceTree = "<group>"; };
|
||||||
D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUI.h; sourceTree = "<group>"; };
|
D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUI.h; sourceTree = "<group>"; };
|
||||||
D29DF0D021E404D4003B2FB9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D29DF0D021E404D4003B2FB9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
@ -473,6 +473,7 @@
|
|||||||
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
|
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
|
||||||
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
|
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
|
||||||
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */,
|
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */,
|
||||||
|
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
|
||||||
);
|
);
|
||||||
path = Molecules;
|
path = Molecules;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -682,7 +683,6 @@
|
|||||||
D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */,
|
D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */,
|
||||||
D2A514562211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.h */,
|
D2A514562211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.h */,
|
||||||
D2A514572211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m */,
|
D2A514572211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m */,
|
||||||
D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */,
|
|
||||||
);
|
);
|
||||||
path = OtherHandlers;
|
path = OtherHandlers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -904,6 +904,7 @@
|
|||||||
D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */,
|
D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */,
|
||||||
DBC4391822442197001AB423 /* CaretView.swift in Sources */,
|
DBC4391822442197001AB423 /* CaretView.swift in Sources */,
|
||||||
D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */,
|
D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */,
|
||||||
|
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
|
||||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
||||||
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
|
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
|
||||||
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
|
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
|
||||||
@ -947,7 +948,6 @@
|
|||||||
D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */,
|
D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */,
|
||||||
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */,
|
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */,
|
||||||
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
||||||
D296E143229729C30051EBE7 /* MoleculeMappingObject+Extension.swift in Sources */,
|
|
||||||
01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */,
|
01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */,
|
||||||
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
|
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
|
||||||
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,
|
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,
|
||||||
|
|||||||
@ -139,4 +139,8 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol, MVMCoreUI
|
|||||||
open func alignment() -> UIStackView.Alignment {
|
open func alignment() -> UIStackView.Alignment {
|
||||||
return UIStackView.Alignment.leading;
|
return UIStackView.Alignment.leading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
return 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -146,6 +146,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
||||||
|
return 31;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - MVMCoreUIViewConstrainingProtocol
|
#pragma mark - MVMCoreUIViewConstrainingProtocol
|
||||||
|
|
||||||
- (BOOL)needsToBeConstrained {
|
- (BOOL)needsToBeConstrained {
|
||||||
|
|||||||
@ -669,6 +669,13 @@
|
|||||||
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
|
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
|
||||||
|
|
||||||
self.primaryButtonType = PrimaryButtonTypeCustom;
|
self.primaryButtonType = PrimaryButtonTypeCustom;
|
||||||
|
NSString *style = [json string:@"style"];
|
||||||
|
if ([style isEqualToString:@"primary"]) {
|
||||||
|
[self setAsStandardCustom];
|
||||||
|
} else if ([style isEqualToString:@"secondary"]) {
|
||||||
|
[self setAsSecondaryCustom];
|
||||||
|
}
|
||||||
|
|
||||||
NSString *color = [json string:@"fillColor"];
|
NSString *color = [json string:@"fillColor"];
|
||||||
if (color) {
|
if (color) {
|
||||||
self.fillColor = [UIColor mfGetColorForHex:color];
|
self.fillColor = [UIColor mfGetColorForHex:color];
|
||||||
@ -691,7 +698,14 @@
|
|||||||
}
|
}
|
||||||
self.validationRequired = [json boolForKey:@"validationRequired"];
|
self.validationRequired = [json boolForKey:@"validationRequired"];
|
||||||
|
|
||||||
[self setAsSmallButton:[json boolForKey:@"small"]];
|
NSString *size = [json string:@"size"];
|
||||||
|
if ([size isEqualToString:@"small"]) {
|
||||||
|
[self setAsSmallButton:YES];
|
||||||
|
} else if ([size isEqualToString:@"tiny"]) {
|
||||||
|
[self setAsTiny:YES];
|
||||||
|
} else {
|
||||||
|
[self setAsSmallButton:NO];
|
||||||
|
}
|
||||||
[self setWithActionMap:json delegateObject:delegateObject additionalData:additionalData];
|
[self setWithActionMap:json delegateObject:delegateObject additionalData:additionalData];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,6 @@
|
|||||||
+ (nullable instancetype)mfDigitTextFieldWithNumberOfDigits:(NSUInteger)numberOfDigits withBothDelegates:(nullable id<UITextFieldDelegate, MFTextFieldDelegate>)delegate;
|
+ (nullable instancetype)mfDigitTextFieldWithNumberOfDigits:(NSUInteger)numberOfDigits withBothDelegates:(nullable id<UITextFieldDelegate, MFTextFieldDelegate>)delegate;
|
||||||
+ (nullable instancetype)mfDigitTextFieldWithNumberOfDigits:(NSUInteger)numberOfDigits withBothDelegates:(nullable id<UITextFieldDelegate, MFTextFieldDelegate>)delegate size:(CGFloat)size;
|
+ (nullable instancetype)mfDigitTextFieldWithNumberOfDigits:(NSUInteger)numberOfDigits withBothDelegates:(nullable id<UITextFieldDelegate, MFTextFieldDelegate>)delegate size:(CGFloat)size;
|
||||||
|
|
||||||
- (void)setMessage:(nullable NSString *)message;
|
|
||||||
|
|
||||||
- (void)setAsSecureTextEntry:(BOOL)secureTextEntry;
|
- (void)setAsSecureTextEntry:(BOOL)secureTextEntry;
|
||||||
|
|
||||||
@property (nullable, nonatomic, strong) NSArray <MFDigitTextBox *>*textFields;
|
@property (nullable, nonatomic, strong) NSArray <MFDigitTextBox *>*textFields;
|
||||||
|
|||||||
@ -18,33 +18,24 @@
|
|||||||
#import "MVMCoreUISplitViewController.h"
|
#import "MVMCoreUISplitViewController.h"
|
||||||
#import "MVMCoreUIUtility.h"
|
#import "MVMCoreUIUtility.h"
|
||||||
#import "MVMCoreUIConstants.h"
|
#import "MVMCoreUIConstants.h"
|
||||||
|
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
||||||
@import MVMCore.MVMCoreDispatchUtility;
|
@import MVMCore.MVMCoreDispatchUtility;
|
||||||
|
|
||||||
@interface MFDigitTextField () <UITextFieldDelegate, MFDigitTextBoxDelegate>
|
@interface MFDigitTextField () <UITextFieldDelegate, MFDigitTextBoxDelegate>
|
||||||
|
|
||||||
@property (nonatomic) NSUInteger numberOfDigits;
|
@property (nonatomic) NSUInteger numberOfDigits;
|
||||||
|
|
||||||
@property (nullable, nonatomic, weak) IBOutlet UILabel *messageLabel;
|
|
||||||
@property (nullable, nonatomic, weak) IBOutlet UIView *textFieldsView;
|
@property (nullable, nonatomic, weak) IBOutlet UIView *textFieldsView;
|
||||||
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *messageToTextFieldPin;
|
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *messageToTextFieldPin;
|
||||||
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *labelToTextFieldPin;
|
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *labelToTextFieldPin;
|
||||||
|
|
||||||
|
|
||||||
@property (nonatomic) BOOL switchedAutomatically;
|
@property (nonatomic) BOOL switchedAutomatically;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MFDigitTextField
|
@implementation MFDigitTextField
|
||||||
|
|
||||||
+ (nullable instancetype)mfTextField {
|
|
||||||
MFDigitTextField *view = [super mfTextField];
|
|
||||||
[MFStyler styleLabelB2:view.messageLabel];
|
|
||||||
[view setMessage:@""];
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MFDigitTextBox *)digitField {
|
- (MFDigitTextBox *)digitField {
|
||||||
|
|
||||||
MFDigitTextBox *textField = [[MFDigitTextBox alloc] init];
|
MFDigitTextBox *textField = [[MFDigitTextBox alloc] init];
|
||||||
textField.delegate = self;
|
textField.delegate = self;
|
||||||
textField.mfTextBoxDelegate = self;
|
textField.mfTextBoxDelegate = self;
|
||||||
@ -128,8 +119,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateView:(CGFloat)size {
|
- (void)updateView:(CGFloat)size {
|
||||||
|
[super updateView:size];
|
||||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||||
[MFStyler styleLabelB2:self.messageLabel];
|
[self.formLabel updateView:size];
|
||||||
|
|
||||||
// Remove all current UI.
|
// Remove all current UI.
|
||||||
if (self.textFields.count > 0) {
|
if (self.textFields.count > 0) {
|
||||||
@ -146,6 +138,29 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setupView {
|
||||||
|
[super setupView];
|
||||||
|
[self.formLabel styleB2:YES];
|
||||||
|
[self setFormText:@""];
|
||||||
|
[self alignCenterHorizontal];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Molecule
|
||||||
|
|
||||||
|
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||||
|
NSNumber *digitsNumber = [json optionalNumberForKey:@"digits"];
|
||||||
|
NSUInteger digits = digitsNumber ? digitsNumber.integerValue : 4;
|
||||||
|
if (digits != self.numberOfDigits) {
|
||||||
|
self.numberOfDigits = digits;
|
||||||
|
[self buildTextFieldsViewForSize:[MVMCoreUIUtility getWidth]];
|
||||||
|
}
|
||||||
|
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
||||||
|
return 44;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Getters
|
#pragma mark - Getters
|
||||||
|
|
||||||
- (NSString *)placeholder {
|
- (NSString *)placeholder {
|
||||||
@ -172,15 +187,13 @@
|
|||||||
|
|
||||||
#pragma mark - Setters
|
#pragma mark - Setters
|
||||||
|
|
||||||
- (void)setMessage:(nullable NSString *)message {
|
- (void)setFormText:(NSString *)formText {
|
||||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
if (formText.length > 0) {
|
||||||
if (message.length > 0) {
|
self.messageToTextFieldPin.constant = 10;
|
||||||
self.messageToTextFieldPin.constant = 10;
|
} else {
|
||||||
} else {
|
self.messageToTextFieldPin.constant = 0;
|
||||||
self.messageToTextFieldPin.constant = 0;
|
}
|
||||||
}
|
[super setFormText:formText];
|
||||||
self.messageLabel.text = message;
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAsSecureTextEntry:(BOOL)secureTextEntry {
|
- (void)setAsSecureTextEntry:(BOOL)secureTextEntry {
|
||||||
@ -284,6 +297,11 @@
|
|||||||
|
|
||||||
- (void)enable:(BOOL)enable {
|
- (void)enable:(BOOL)enable {
|
||||||
[super enable:enable];
|
[super enable:enable];
|
||||||
|
if (enable) {
|
||||||
|
[self.formLabel styleB2:YES];
|
||||||
|
} else {
|
||||||
|
self.formLabel.textColor = [UIColor mfBattleshipGrey];
|
||||||
|
}
|
||||||
for (UITextField *textField in self.textFields) {
|
for (UITextField *textField in self.textFields) {
|
||||||
textField.userInteractionEnabled = enable;
|
textField.userInteractionEnabled = enable;
|
||||||
textField.enabled = enable;
|
textField.enabled = enable;
|
||||||
|
|||||||
@ -1,24 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait">
|
<device id="retina4_7" orientation="portrait">
|
||||||
<adaptation id="fullscreen"/>
|
<adaptation id="fullscreen"/>
|
||||||
</device>
|
</device>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<customFonts key="customFonts">
|
|
||||||
<array key="NHaasGroteskDSStd-65Md.otf">
|
|
||||||
<string>NHaasGroteskDSStd-65Md</string>
|
|
||||||
</array>
|
|
||||||
</customFonts>
|
|
||||||
<objects>
|
<objects>
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MFDigitTextField">
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MFDigitTextField">
|
||||||
<connections>
|
<connections>
|
||||||
|
<outlet property="formLabel" destination="lBe-qk-qFb" id="Z62-sL-6ri"/>
|
||||||
<outlet property="label" destination="FWB-f6-Irs" id="fcc-SH-O4s"/>
|
<outlet property="label" destination="FWB-f6-Irs" id="fcc-SH-O4s"/>
|
||||||
<outlet property="labelToTextFieldPin" destination="KyA-DB-529" id="SOG-MG-gMN"/>
|
<outlet property="labelToTextFieldPin" destination="KyA-DB-529" id="SOG-MG-gMN"/>
|
||||||
<outlet property="messageLabel" destination="lBe-qk-qFb" id="x3K-fb-b4U"/>
|
|
||||||
<outlet property="messageToTextFieldPin" destination="NPs-pX-DJ0" id="41B-cE-pax"/>
|
<outlet property="messageToTextFieldPin" destination="NPs-pX-DJ0" id="41B-cE-pax"/>
|
||||||
<outlet property="textFieldsView" destination="v46-w7-vQ1" id="hh8-TK-7XM"/>
|
<outlet property="textFieldsView" destination="v46-w7-vQ1" id="hh8-TK-7XM"/>
|
||||||
</connections>
|
</connections>
|
||||||
@ -28,7 +23,7 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="320" height="80"/>
|
<rect key="frame" x="0.0" y="0.0" width="320" height="80"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="800" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="900" verticalCompressionResistancePriority="1000" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lBe-qk-qFb">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="800" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="900" verticalCompressionResistancePriority="1000" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lBe-qk-qFb" customClass="Label" customModule="MVMCoreUI" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="320" height="16"/>
|
<rect key="frame" x="0.0" y="0.0" width="320" height="16"/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
<fontDescription key="fontDescription" name="NHaasGroteskDSStd-65Md" family="Neue Haas Grotesk Display Std" pointSize="13"/>
|
<fontDescription key="fontDescription" name="NHaasGroteskDSStd-65Md" family="Neue Haas Grotesk Display Std" pointSize="13"/>
|
||||||
|
|||||||
@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textContainerRightPin;
|
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textContainerRightPin;
|
||||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *errorLableRightPin;
|
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *errorLableRightPin;
|
||||||
@property (nonatomic) BOOL isMolecule;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -42,7 +41,7 @@
|
|||||||
- (void)updateView:(CGFloat)size {
|
- (void)updateView:(CGFloat)size {
|
||||||
[super updateView:size];
|
[super updateView:size];
|
||||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||||
self.formLabel.font = [MFStyler fontB3];
|
[self.formLabel updateView:size];
|
||||||
self.label.font = [MFStyler fontForTextFieldUnderLabel];
|
self.label.font = [MFStyler fontForTextFieldUnderLabel];
|
||||||
[MFStyler styleTextField:self.textField];
|
[MFStyler styleTextField:self.textField];
|
||||||
[self.dashLine updateView:size];
|
[self.dashLine updateView:size];
|
||||||
@ -55,11 +54,13 @@
|
|||||||
UINib *nib = [self getNib];
|
UINib *nib = [self getNib];
|
||||||
NSArray *views = [nib instantiateWithOwner:self options:nil];
|
NSArray *views = [nib instantiateWithOwner:self options:nil];
|
||||||
UIView *view = [views firstObject];
|
UIView *view = [views firstObject];
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
[view setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
[view setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
||||||
[view setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
[view setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
||||||
self.view = view;
|
self.view = view;
|
||||||
view.frame = self.frame;
|
view.frame = self.frame;
|
||||||
[self addSubview:view];
|
[self addSubview:view];
|
||||||
|
[self pinViewToSuperView:view];
|
||||||
|
|
||||||
self.textField.font = [MFStyler fontForTextField];
|
self.textField.font = [MFStyler fontForTextField];
|
||||||
self.translatesAutoresizingMaskIntoConstraints = NO;
|
self.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
@ -556,10 +557,6 @@
|
|||||||
|
|
||||||
#pragma mark - MVMCoreUIMoleculeViewProtocol
|
#pragma mark - MVMCoreUIMoleculeViewProtocol
|
||||||
|
|
||||||
- (void)setAsMolecule {
|
|
||||||
self.isMolecule = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||||
if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) {
|
if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) {
|
||||||
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
|
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
|
||||||
@ -572,6 +569,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
||||||
|
return 76;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - FormValidationProtocol
|
#pragma mark - FormValidationProtocol
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -108,10 +108,6 @@ open class CaretView: MFView {
|
|||||||
// Configure class properties with JSON values
|
// Configure class properties with JSON values
|
||||||
guard let dictionary = json else { return }
|
guard let dictionary = json else { return }
|
||||||
|
|
||||||
if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String {
|
|
||||||
backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let strokeColorHex = dictionary["strokeColor"] as? String {
|
if let strokeColorHex = dictionary["strokeColor"] as? String {
|
||||||
strokeColor = UIColor.mfGet(forHex: strokeColorHex)
|
strokeColor = UIColor.mfGet(forHex: strokeColorHex)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,10 +74,6 @@ open class DashLine: MFView {
|
|||||||
// Configure class properties with JSON values
|
// Configure class properties with JSON values
|
||||||
guard let jsonDictionary = json else { return }
|
guard let jsonDictionary = json else { return }
|
||||||
|
|
||||||
if let backgroundColorHex = jsonDictionary[KeyBackgroundColor] as? String {
|
|
||||||
backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let isHiddenValue = jsonDictionary[KeyIsHidden] as? Bool {
|
if let isHiddenValue = jsonDictionary[KeyIsHidden] as? Bool {
|
||||||
isHidden = isHiddenValue
|
isHidden = isHiddenValue
|
||||||
}
|
}
|
||||||
|
|||||||
@ -247,10 +247,11 @@ public typealias ActionBlock = () -> Void
|
|||||||
case "action":
|
case "action":
|
||||||
guard let actionLabel = label as? Label else { continue }
|
guard let actionLabel = label as? Label else { continue }
|
||||||
|
|
||||||
actionLabel.addTappableLinkAttribute(range: range,
|
actionLabel.addActionAttributes(range: range, string: attributedString)
|
||||||
actionMap: json,
|
actionLabel.clauses.append(ActionableClause(range: range,
|
||||||
additionalData: additionalData,
|
actionBlock: actionLabel.createActionBlockFrom(actionMap: json,
|
||||||
delegateObject: delegate)
|
additionalData: additionalData,
|
||||||
|
delegateObject: delegate)))
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -397,13 +398,18 @@ extension Label {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func setDefaultAttributes(range: NSRange) {
|
func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) {
|
||||||
|
|
||||||
|
guard let string = string else { return }
|
||||||
|
string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func setActionAttributes(range: NSRange) {
|
||||||
|
|
||||||
guard let attributedText = attributedText else { return }
|
guard let attributedText = attributedText else { return }
|
||||||
|
|
||||||
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||||
mutableAttributedString.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range)
|
addActionAttributes(range: range, string: mutableAttributedString)
|
||||||
|
|
||||||
self.attributedText = mutableAttributedString
|
self.attributedText = mutableAttributedString
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +423,7 @@ extension Label {
|
|||||||
*/
|
*/
|
||||||
@objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) {
|
@objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) {
|
||||||
|
|
||||||
setDefaultAttributes(range: range)
|
setActionAttributes(range: range)
|
||||||
clauses.append(ActionableClause(range: range, actionBlock: actionBlock))
|
clauses.append(ActionableClause(range: range, actionBlock: actionBlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +439,7 @@ extension Label {
|
|||||||
*/
|
*/
|
||||||
@objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
@objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
|
|
||||||
setDefaultAttributes(range: range)
|
setActionAttributes(range: range)
|
||||||
clauses.append(ActionableClause(range: range,
|
clauses.append(ActionableClause(range: range,
|
||||||
actionBlock: createActionBlockFrom(actionMap: actionMap,
|
actionBlock: createActionBlockFrom(actionMap: actionMap,
|
||||||
additionalData: additionalData,
|
additionalData: additionalData,
|
||||||
|
|||||||
@ -170,10 +170,6 @@ import Foundation
|
|||||||
leftTextLabel.setWithJSON(dictionary.optionalDictionaryForKey("leftText"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData)
|
leftTextLabel.setWithJSON(dictionary.optionalDictionaryForKey("leftText"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData)
|
||||||
rightTextLabel.setWithJSON(dictionary.optionalDictionaryForKey("rightText"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData)
|
rightTextLabel.setWithJSON(dictionary.optionalDictionaryForKey("rightText"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String {
|
|
||||||
backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !leftTextLabel.hasText {
|
if !leftTextLabel.hasText {
|
||||||
constrainRightLabel()
|
constrainRightLabel()
|
||||||
} else if !rightTextLabel.hasText {
|
} else if !rightTextLabel.hasText {
|
||||||
|
|||||||
@ -18,12 +18,17 @@ import UIKit
|
|||||||
var heightConstraint: NSLayoutConstraint?
|
var heightConstraint: NSLayoutConstraint?
|
||||||
var loadingSpinnerHeightConstraint: NSLayoutConstraint?
|
var loadingSpinnerHeightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
// Allows for a view to hardcode which height to use if there is none in the json.
|
||||||
|
var imageWidth: CGFloat?
|
||||||
|
var imageHeight: CGFloat?
|
||||||
|
|
||||||
// For keeping track of current state.
|
// For keeping track of current state.
|
||||||
var edges: UIRectEdge?
|
private var edges: UIRectEdge?
|
||||||
var spinnerHeight: CGFloat?
|
private var spinnerHeight: CGFloat?
|
||||||
var width: CGFloat?
|
private var currentImageWidth: CGFloat?
|
||||||
var loadingImageName: String?
|
private var currentImageHeight: CGFloat?
|
||||||
var isFallbackImage: Bool = false
|
private var currentImageName: String?
|
||||||
|
private var isFallbackImage: Bool = false
|
||||||
|
|
||||||
public init(pinnedEdges edge: UIRectEdge) {
|
public init(pinnedEdges edge: UIRectEdge) {
|
||||||
edges = edge
|
edges = edge
|
||||||
@ -50,62 +55,24 @@ import UIKit
|
|||||||
imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: NSLayoutConstraint.Axis.vertical)
|
imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: NSLayoutConstraint.Axis.vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let topPin = topPin {
|
if edge.contains(UIRectEdge.top) && edge.contains(UIRectEdge.bottom) {
|
||||||
removeConstraint(topPin)
|
alignFillVertical()
|
||||||
}
|
} else if edge.contains(UIRectEdge.top) {
|
||||||
if edge.contains(UIRectEdge.top) {
|
alignTop()
|
||||||
topPin = imageView.topAnchor.constraint(equalTo: topAnchor)
|
} else if edge.contains(UIRectEdge.bottom) {
|
||||||
|
alignBottom()
|
||||||
} else {
|
} else {
|
||||||
topPin = imageView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor)
|
alignCenterVertical()
|
||||||
}
|
}
|
||||||
topPin?.isActive = true
|
|
||||||
|
|
||||||
if let bottomPin = bottomPin {
|
if edge.contains(UIRectEdge.left) && edge.contains(UIRectEdge.right) {
|
||||||
removeConstraint(bottomPin)
|
alignFillHorizontal()
|
||||||
}
|
} else if edge.contains(UIRectEdge.left) {
|
||||||
if edge.contains(UIRectEdge.bottom) {
|
alignLeft()
|
||||||
bottomPin = bottomAnchor.constraint(equalTo: imageView.bottomAnchor)
|
} else if edge.contains(UIRectEdge.right) {
|
||||||
|
alignRight()
|
||||||
} else {
|
} else {
|
||||||
bottomPin = bottomAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor)
|
alignCenterHorizontal()
|
||||||
}
|
|
||||||
bottomPin?.isActive = true
|
|
||||||
|
|
||||||
if let leftPin = leftPin {
|
|
||||||
removeConstraint(leftPin)
|
|
||||||
}
|
|
||||||
if edge.contains(UIRectEdge.left) {
|
|
||||||
leftPin = imageView.leftAnchor.constraint(equalTo: leftAnchor)
|
|
||||||
} else {
|
|
||||||
leftPin = imageView.leftAnchor.constraint(greaterThanOrEqualTo: leftAnchor)
|
|
||||||
}
|
|
||||||
leftPin?.isActive = true
|
|
||||||
|
|
||||||
if let rightPin = rightPin {
|
|
||||||
removeConstraint(rightPin)
|
|
||||||
}
|
|
||||||
if edge.contains(UIRectEdge.right) {
|
|
||||||
rightPin = rightAnchor.constraint(equalTo: imageView.rightAnchor)
|
|
||||||
} else {
|
|
||||||
rightPin = rightAnchor.constraint(greaterThanOrEqualTo: imageView.rightAnchor)
|
|
||||||
}
|
|
||||||
rightPin?.isActive = true
|
|
||||||
|
|
||||||
// If neither the top or the bottom are pinned, center it.
|
|
||||||
if let centerY = centerY {
|
|
||||||
removeConstraint(centerY)
|
|
||||||
}
|
|
||||||
if !edge.contains(UIRectEdge.top) && !edge.contains(UIRectEdge.bottom) {
|
|
||||||
centerY = imageView.centerYAnchor.constraint(equalTo: centerYAnchor)
|
|
||||||
centerY?.isActive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If neither the left or the right are pinned, center it.
|
|
||||||
if let centerX = centerX {
|
|
||||||
removeConstraint(centerX)
|
|
||||||
}
|
|
||||||
if !edge.contains(UIRectEdge.left) && !edge.contains(UIRectEdge.right) {
|
|
||||||
centerX = imageView.centerXAnchor.constraint(equalTo: centerXAnchor)
|
|
||||||
centerX?.isActive = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +88,7 @@ import UIKit
|
|||||||
// Setup image.
|
// Setup image.
|
||||||
imageView.translatesAutoresizingMaskIntoConstraints = false;
|
imageView.translatesAutoresizingMaskIntoConstraints = false;
|
||||||
addSubview(imageView)
|
addSubview(imageView)
|
||||||
|
pinView(toSuperView: imageView)
|
||||||
|
|
||||||
// Setup edges constraints
|
// Setup edges constraints
|
||||||
if edges == nil {
|
if edges == nil {
|
||||||
@ -159,10 +127,30 @@ import UIKit
|
|||||||
|
|
||||||
open func shouldLoadImage(withName imageName: String?, width: CGFloat) -> Bool {
|
open func shouldLoadImage(withName imageName: String?, width: CGFloat) -> Bool {
|
||||||
// We should load a new image if there is no current image, the image names are different, the width is different, or we are using a fallback image.
|
// We should load a new image if there is no current image, the image names are different, the width is different, or we are using a fallback image.
|
||||||
guard let currentWidth = self.width else {
|
guard let currentWidth = self.currentImageWidth else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return (imageView.image == nil && imageView.animatedImage == nil) || imageName != loadingImageName || !MVMCoreGetterUtility.cgfequal(width, currentWidth) || self.isFallbackImage
|
return (imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || !MVMCoreGetterUtility.cgfequal(width, currentWidth) || isFallbackImage
|
||||||
|
}
|
||||||
|
|
||||||
|
open func shouldLoadImage(withName imageName: String?, width: CGFloat?, height: CGFloat?) -> Bool {
|
||||||
|
// We should load a new image if there is no current image, the image names are different, or we are using a fallback image.
|
||||||
|
if ((imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || isFallbackImage) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// load new image if the width is different
|
||||||
|
if let oldWidth = self.currentImageWidth, let newWidth = width, !MVMCoreGetterUtility.cgfequal(oldWidth, newWidth) {
|
||||||
|
return true
|
||||||
|
} else if (self.currentImageWidth == nil) != (width == nil) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// load new image if the height is different
|
||||||
|
if let oldHeight = self.currentImageHeight, let newHeight = height, !MVMCoreGetterUtility.cgfequal(oldHeight, newHeight) {
|
||||||
|
return true
|
||||||
|
} else if (self.currentImageHeight == nil) || (height == nil) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect.
|
// Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect.
|
||||||
@ -191,43 +179,44 @@ import UIKit
|
|||||||
imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.vertical)
|
imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
// MARK: - MVMCoreUIMoleculeViewProtocol functions
|
||||||
super.updateView(size)
|
open override func setAsMolecule() {
|
||||||
let width = size.rounded()
|
addSizeConstraintsForAspectRatio = true
|
||||||
if let imageName = json?.optionalStringForKey("image"), shouldLoadImage(withName: imageName, width: width) {
|
}
|
||||||
imageView.image = nil
|
|
||||||
imageView.animatedImage = nil
|
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
loadImage(withName: imageName, format: json?.optionalStringForKey("imageFormat"), width: NSNumber(value: Double(width)), height: nil, customFallbackImage: json?.optionalStringForKey("fallbackImage"))
|
return json?.optionalCGFloatForKey("height") ?? 0
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol functions
|
|
||||||
open 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)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
|
||||||
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
|
|
||||||
}
|
|
||||||
if let accessibilityString = json?.optionalStringForKey("accessibilityText") {
|
if let accessibilityString = json?.optionalStringForKey("accessibilityText") {
|
||||||
imageView.accessibilityLabel = accessibilityString
|
imageView.accessibilityLabel = accessibilityString
|
||||||
imageView.accessibilityTraits = .staticText
|
imageView.accessibilityTraits = .staticText
|
||||||
imageView.isAccessibilityElement = true
|
imageView.isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
let width = json?.optionalCGFloatForKey("width") ?? imageWidth
|
||||||
|
let height = json?.optionalCGFloatForKey("height") ?? imageHeight
|
||||||
|
if let imageName = json?.optionalStringForKey("image"), shouldLoadImage(withName: imageName, width: width, height: height) {
|
||||||
|
imageView.image = nil
|
||||||
|
imageView.animatedImage = nil
|
||||||
|
loadImage(withName: imageName, format: json?.optionalStringForKey("imageFormat"), width: width as NSNumber?, height: height as NSNumber?, customFallbackImage: json?.optionalStringForKey("fallbackImage"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - load functions
|
// MARK: - load functions
|
||||||
public func loadImage(withName imageName: String?, format: String?, width: NSNumber?, height: NSNumber?, customFallbackImage: String?, completionHandler: @escaping MVMCoreGetImageBlock) {
|
public func loadImage(withName imageName: String?, format: String?, width: NSNumber?, height: NSNumber?, customFallbackImage: String?, completionHandler: @escaping MVMCoreGetImageBlock) {
|
||||||
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
||||||
self.loadingImageName = imageName
|
self.currentImageName = imageName
|
||||||
if let width = width {
|
self.currentImageWidth = width?.cgfloat()
|
||||||
self.width = width.cgfloat()
|
self.currentImageHeight = height?.cgfloat()
|
||||||
}
|
|
||||||
self.loadingSpinner.resumeSpinnerAfterDelay()
|
self.loadingSpinner.resumeSpinnerAfterDelay()
|
||||||
if let height = self.spinnerHeight {
|
if let height = self.spinnerHeight {
|
||||||
self.loadingSpinnerHeightConstraint?.constant = height
|
self.loadingSpinnerHeightConstraint?.constant = height
|
||||||
}
|
}
|
||||||
|
|
||||||
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
||||||
guard let loadingImageName = self?.loadingImageName, loadingImageName == imageName else {
|
guard let loadingImageName = self?.currentImageName, loadingImageName == imageName else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self?.isFallbackImage = isFallbackImage
|
self?.isFallbackImage = isFallbackImage
|
||||||
@ -250,14 +239,14 @@ import UIKit
|
|||||||
public func loadCroppedImage(withName imageName:
|
public func loadCroppedImage(withName imageName:
|
||||||
String?, width: NSNumber?, height: NSNumber?, cropRect: CGRect, flipImage: Bool, customFallbackImage: String?) {
|
String?, width: NSNumber?, height: NSNumber?, cropRect: CGRect, flipImage: Bool, customFallbackImage: String?) {
|
||||||
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
||||||
self.loadingImageName = imageName
|
self.currentImageName = imageName
|
||||||
self.loadingSpinner.resumeSpinnerAfterDelay()
|
self.loadingSpinner.resumeSpinnerAfterDelay()
|
||||||
if let height = self.spinnerHeight {
|
if let height = self.spinnerHeight {
|
||||||
self.loadingSpinnerHeightConstraint?.constant = height
|
self.loadingSpinnerHeightConstraint?.constant = height
|
||||||
}
|
}
|
||||||
MVMCoreCache.shared()?.getCroppedImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, finalRect: cropRect, flipImage: flipImage, localFallbackImageName: customFallbackImage ?? MVMCoreUIUtility.localizedImageName("fallback"), completionHandler: { [weak self] (image, data, isFallBackImage) in
|
MVMCoreCache.shared()?.getCroppedImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, finalRect: cropRect, flipImage: flipImage, localFallbackImageName: customFallbackImage ?? MVMCoreUIUtility.localizedImageName("fallback"), completionHandler: { [weak self] (image, data, isFallBackImage) in
|
||||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||||
guard let image = image, let loadingImageName = self?.loadingImageName, loadingImageName == imageName else {
|
guard let image = image, let loadingImageName = self?.currentImageName, loadingImageName == imageName else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self?.loadingSpinnerHeightConstraint?.constant = 0
|
self?.loadingSpinnerHeightConstraint?.constant = 0
|
||||||
|
|||||||
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#import "MFView.h"
|
#import "MFView.h"
|
||||||
@import MVMCore.Swift;
|
@import MVMCore.Swift;
|
||||||
|
@import MVMCore.NSDictionary_MFConvenience;
|
||||||
|
#import "MVMCoreUIConstants.h"
|
||||||
|
#import "UIColor+MFConvenience.h"
|
||||||
|
|
||||||
@implementation MFView
|
@implementation MFView
|
||||||
|
|
||||||
@ -46,6 +49,11 @@
|
|||||||
|
|
||||||
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||||
self.json = json;
|
self.json = json;
|
||||||
|
|
||||||
|
NSString *colorString = [json string:KeyBackgroundColor];
|
||||||
|
if (colorString) {
|
||||||
|
self.backgroundColor = [UIColor mfGetColorForHex:colorString];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -78,6 +78,9 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
|
|||||||
additionalData: additionalData];
|
additionalData: additionalData];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
||||||
|
return CheckBoxHeightWidth;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - convenient class methods
|
#pragma mark - convenient class methods
|
||||||
|
|
||||||
|
|||||||
@ -31,4 +31,6 @@ typedef void(^ValueChangeBlock)(void);
|
|||||||
// Sets the state without triggering the value changed block.
|
// Sets the state without triggering the value changed block.
|
||||||
- (void)setState:(BOOL)stateWithoutBlock withoutBlockAnimated:(BOOL)animated;
|
- (void)setState:(BOOL)stateWithoutBlock withoutBlockAnimated:(BOOL)animated;
|
||||||
|
|
||||||
|
+ (CGFloat)getSwitchHeight;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import <MVMCoreUI/MFView.h>
|
#import <MVMCoreUI/MFView.h>
|
||||||
|
#import <MVMCoreUI/MVMCoreUIViewConstrainingProtocol.h>
|
||||||
@class MFSizeObject;
|
@class MFSizeObject;
|
||||||
|
|
||||||
typedef enum : NSUInteger {
|
typedef enum : NSUInteger {
|
||||||
@ -15,7 +16,7 @@ typedef enum : NSUInteger {
|
|||||||
SeparatorPositionBot
|
SeparatorPositionBot
|
||||||
} SeparatorPosition;
|
} SeparatorPosition;
|
||||||
|
|
||||||
@interface SeparatorView : MFView
|
@interface SeparatorView : MFView <MVMCoreUIViewConstrainingProtocol>
|
||||||
|
|
||||||
@property (nullable, weak, nonatomic) NSLayoutConstraint *height;
|
@property (nullable, weak, nonatomic) NSLayoutConstraint *height;
|
||||||
@property (nullable, weak, nonatomic) NSLayoutConstraint *leftPin;
|
@property (nullable, weak, nonatomic) NSLayoutConstraint *leftPin;
|
||||||
|
|||||||
@ -70,10 +70,6 @@
|
|||||||
|
|
||||||
#pragma mark - set up
|
#pragma mark - set up
|
||||||
|
|
||||||
- (void)reset {
|
|
||||||
[self setAsLight];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)updateView:(CGFloat)size {
|
- (void)updateView:(CGFloat)size {
|
||||||
[super updateView:size];
|
[super updateView:size];
|
||||||
self.height.constant = [self.heightSizeObject getValueBasedOnSize:size];
|
self.height.constant = [self.heightSizeObject getValueBasedOnSize:size];
|
||||||
@ -115,10 +111,6 @@
|
|||||||
[self setAsLight];
|
[self setAsLight];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NSString *backgroundColor = [json string:KeyBackgroundColor];
|
|
||||||
if (backgroundColor) {
|
|
||||||
self.backgroundColor = [UIColor mfGetColorForHex:backgroundColor];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.hidden = YES;
|
self.hidden = YES;
|
||||||
}
|
}
|
||||||
@ -165,5 +157,34 @@
|
|||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self layoutIfNeeded];
|
[self layoutIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Molecule
|
||||||
|
|
||||||
|
- (void)reset {
|
||||||
|
[self setAsLight];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)needsToBeConstrained {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)copyBackgroundColor {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
|
||||||
|
NSString *type = [json string:KeyType];
|
||||||
|
if ([type isEqualToString:@"none"]) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if ([type isEqualToString:@"medium"]) {
|
||||||
|
return 2;
|
||||||
|
} else if ([type isEqualToString:@"heavy"]) {
|
||||||
|
return 4;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -12,23 +12,23 @@
|
|||||||
@interface ViewConstrainingView : MFView
|
@interface ViewConstrainingView : MFView
|
||||||
|
|
||||||
// Dont set these directly.
|
// Dont set these directly.
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *leftPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *leftPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *rightPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *rightPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *topPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *topPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *bottomPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *bottomPin;
|
||||||
|
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *alignCenterPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterLeftPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *alignCenterLeftPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterRightPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *alignCenterRightPin;
|
||||||
|
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterVerticalPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *alignCenterVerticalPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterTopPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *alignCenterTopPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterBottomPin;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *alignCenterBottomPin;
|
||||||
|
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *leftPinLow;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *leftPinLow;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *rightPinLow;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *rightPinLow;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *topPinLow;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *topPinLow;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *bottomPinLow;
|
@property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *bottomPinLow;
|
||||||
|
|
||||||
|
|
||||||
// In updateView, will set horizontal padding to default if set to YES.
|
// In updateView, will set horizontal padding to default if set to YES.
|
||||||
|
|||||||
@ -48,11 +48,21 @@
|
|||||||
#pragma mark - Constraining
|
#pragma mark - Constraining
|
||||||
|
|
||||||
- (void)pinViewToSuperView:(nonnull UIView *)view {
|
- (void)pinViewToSuperView:(nonnull UIView *)view {
|
||||||
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubviewToSuperview:view];
|
NSLayoutConstraint *constraint = [view.leftAnchor constraintEqualToAnchor:view.superview.leftAnchor];
|
||||||
self.leftPin = dictionary[ConstraintLeading];
|
constraint.active = YES;
|
||||||
self.topPin = dictionary[ConstraintTop];
|
self.leftPin = constraint;
|
||||||
self.bottomPin = dictionary[ConstraintBot];
|
|
||||||
self.rightPin = dictionary[ConstraintTrailing];
|
constraint = [view.topAnchor constraintEqualToAnchor:view.superview.topAnchor];
|
||||||
|
constraint.active = YES;
|
||||||
|
self.topPin = constraint;
|
||||||
|
|
||||||
|
constraint = [view.superview.rightAnchor constraintEqualToAnchor:view.rightAnchor];
|
||||||
|
constraint.active = YES;
|
||||||
|
self.rightPin = constraint;
|
||||||
|
|
||||||
|
constraint = [view.superview.bottomAnchor constraintEqualToAnchor:view.bottomAnchor];
|
||||||
|
constraint.active = YES;
|
||||||
|
self.bottomPin = constraint;
|
||||||
|
|
||||||
self.alignCenterPin = [view.centerXAnchor constraintEqualToAnchor:view.superview.centerXAnchor];
|
self.alignCenterPin = [view.centerXAnchor constraintEqualToAnchor:view.superview.centerXAnchor];
|
||||||
self.alignCenterLeftPin = [view.leftAnchor constraintGreaterThanOrEqualToAnchor:view.superview.leftAnchor];
|
self.alignCenterLeftPin = [view.leftAnchor constraintGreaterThanOrEqualToAnchor:view.superview.leftAnchor];
|
||||||
@ -267,6 +277,9 @@
|
|||||||
- (void)shouldSetHorizontalMargins:(BOOL)shouldSet {
|
- (void)shouldSetHorizontalMargins:(BOOL)shouldSet {
|
||||||
self.updateViewHorizontalDefaults = shouldSet;
|
self.updateViewHorizontalDefaults = shouldSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)shouldSetVerticalMargins:(BOOL)shouldSet {
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - MVMCoreViewProtocol
|
#pragma mark - MVMCoreViewProtocol
|
||||||
|
|
||||||
@ -312,7 +325,9 @@
|
|||||||
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||||
if (self.molecule) {
|
if (self.molecule) {
|
||||||
[self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
[self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||||
self.backgroundColor = self.molecule.backgroundColor;
|
}
|
||||||
|
if (self.constrainedView && (![self.constrainedView respondsToSelector:@selector(copyBackgroundColor)] || [self.constrainedView performSelector:@selector(copyBackgroundColor)])) {
|
||||||
|
self.backgroundColor = self.constrainedView.backgroundColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -89,6 +89,9 @@
|
|||||||
// Returns if the screen size has changed.
|
// Returns if the screen size has changed.
|
||||||
- (BOOL)screenSizeChanged;
|
- (BOOL)screenSizeChanged;
|
||||||
|
|
||||||
|
/// If we have new data, this is called. It calls newDataBuildScreen and sets the ui to update.
|
||||||
|
- (void)newDataBuildAndUpdate;
|
||||||
|
|
||||||
#pragma mark - Functions To Subclass
|
#pragma mark - Functions To Subclass
|
||||||
|
|
||||||
// This view controller should subclass this function and check the load to make sure it has all the needed data. Fills the error object if there are any errors. Returns if we should finish the load or not.
|
// This view controller should subclass this function and check the load to make sure it has all the needed data. Fills the error object if there are any errors. Returns if we should finish the load or not.
|
||||||
@ -131,11 +134,20 @@
|
|||||||
// Returns an array of modules to observe for when we receive a response with JSON. Subclass this to have the ui update when the returned page types are cached.
|
// Returns an array of modules to observe for when we receive a response with JSON. Subclass this to have the ui update when the returned page types are cached.
|
||||||
- (nullable NSArray *)modulesToListenFor;
|
- (nullable NSArray *)modulesToListenFor;
|
||||||
|
|
||||||
// The function that gets called by the notification center when the JSON is updated.
|
/// The function that gets called by the notification center when the JSON is updated, if we have anything we are listening for (pageTypesToListenFor, modulesToListenFor). This function also tells the screen to update (newDataBuildAndUpdate) if we received new json that we were listening for.
|
||||||
- (void)responseJSONUpdated:(nonnull NSNotification *)notification;
|
- (void)responseJSONUpdated:(nonnull NSNotification *)notification;
|
||||||
|
|
||||||
// Updates the json dictionary and the screen with the passed in dictionary. Subclass to get any custom behavior if necessary.
|
/// Sets the page on the load object. Default returns true. Return true if the page is loaded and newDataBuildAndUpdate needs to happen. Can subclass to avoid this.
|
||||||
- (void)updateWithResponsePage:(nullable NSDictionary *)page modules:(nullable NSDictionary *)modules;
|
- (BOOL)newPageLoaded:(nonnull NSDictionary *)page;
|
||||||
|
|
||||||
|
/// Appends to the modules on the load object. Default returns true. Return true if the modules are loaded and newDataBuildAndUpdate needs to happen. Can subclass to avoid this.
|
||||||
|
- (BOOL)newModulesLoaded:(nonnull NSDictionary *)modules;
|
||||||
|
|
||||||
|
/** Verifies that all needed modules are loaded
|
||||||
|
* @param loadObject The load data from the cache or server.
|
||||||
|
* @param error The error object passed in will be set in the case of an error.
|
||||||
|
* @return True if the calling process should continue. */
|
||||||
|
+ (BOOL)verifyRequiredModulesLoadedForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(MVMCoreErrorObject *_Nonnull *_Nonnull)error;
|
||||||
|
|
||||||
#pragma mark - Navigation Item, Menu, Support, Top Alert
|
#pragma mark - Navigation Item, Menu, Support, Top Alert
|
||||||
|
|
||||||
|
|||||||
@ -93,9 +93,11 @@
|
|||||||
#pragma mark - Functions To Subclass
|
#pragma mark - Functions To Subclass
|
||||||
|
|
||||||
- (BOOL)shouldFinishProcessingLoad:(nonnull MVMCoreLoadObject *)loadObject error:(MVMCoreErrorObject *_Nonnull *_Nonnull)error {
|
- (BOOL)shouldFinishProcessingLoad:(nonnull MVMCoreLoadObject *)loadObject error:(MVMCoreErrorObject *_Nonnull *_Nonnull)error {
|
||||||
self.loadObject = loadObject;
|
|
||||||
self.pageType = loadObject.pageType;
|
self.pageType = loadObject.pageType;
|
||||||
return YES;
|
self.loadObject = loadObject;
|
||||||
|
|
||||||
|
// Verifies all modules needed are loaded.
|
||||||
|
return [MFViewController verifyRequiredModulesLoadedForLoadObject:loadObject error:error];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the screen to use the screen heading.
|
// Sets the screen to use the screen heading.
|
||||||
@ -213,53 +215,83 @@
|
|||||||
// Checks for a page we are listening for.
|
// Checks for a page we are listening for.
|
||||||
NSArray *pageTypesListeningFor = [self pageTypesToListenFor];
|
NSArray *pageTypesListeningFor = [self pageTypesToListenFor];
|
||||||
NSDictionary *pages = [notification.userInfo dict:KeyPageMap];
|
NSDictionary *pages = [notification.userInfo dict:KeyPageMap];
|
||||||
__block NSDictionary *pageUpdated = nil;
|
__block BOOL newData = NO;
|
||||||
[pageTypesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull pageToListenFor, NSUInteger idx, BOOL * _Nonnull stop) {
|
[pageTypesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull pageToListenFor, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||||
NSDictionary *page = [pages dict:pageToListenFor];
|
NSDictionary *page = [pages dict:pageToListenFor];
|
||||||
if (page) {
|
NSString *pageType = [page string:KeyPageType];
|
||||||
pageUpdated = page;
|
if (page && [pageType isEqualToString:self.pageType]) {
|
||||||
|
newData = [self newPageLoaded:page];
|
||||||
*stop = YES;
|
*stop = YES;
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Checks for modules we are listening for.
|
// Checks for modules we are listening for.
|
||||||
NSArray *modulesListeningFor = [self modulesToListenFor];
|
NSArray *modulesListeningFor = [self modulesToListenFor];
|
||||||
NSDictionary *modules = [notification.userInfo dict:KeyModuleMap];
|
NSDictionary *modulesReceived = [notification.userInfo dict:KeyModuleMap];
|
||||||
__block NSMutableDictionary *modulesUpdated = [NSMutableDictionary dictionary];
|
__block NSMutableDictionary *modulesUpdated = [NSMutableDictionary dictionary];
|
||||||
[modulesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull moduleToListenFor, NSUInteger idx, BOOL * _Nonnull stop) {
|
[modulesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull moduleToListenFor, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||||
NSDictionary *module = [modules dict:moduleToListenFor];
|
NSDictionary *module = [modulesReceived dict:moduleToListenFor];
|
||||||
if (module) {
|
if (module) {
|
||||||
[modulesUpdated setObject:module forKey:moduleToListenFor];
|
[modulesUpdated setObject:module forKey:moduleToListenFor];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
if (modulesUpdated.count > 0) {
|
||||||
|
newData = [self newModulesLoaded:modulesUpdated];
|
||||||
|
}
|
||||||
|
|
||||||
[self updateWithResponsePage:pageUpdated modules:modulesUpdated];
|
if (newData) {
|
||||||
|
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||||
|
[self newDataBuildAndUpdate];
|
||||||
|
}];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateWithResponsePage:(nullable NSDictionary *)page modules:(nullable NSDictionary *)modules {
|
- (BOOL)newPageLoaded:(nonnull NSDictionary *)page {
|
||||||
|
self.loadObject.pageJSON = page;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)newModulesLoaded:(nonnull NSDictionary *)modules {
|
||||||
|
if (self.loadObject.modulesJSON) {
|
||||||
|
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:self.loadObject.modulesJSON];
|
||||||
|
[mutableDictionary addEntriesFromDictionary:modules];
|
||||||
|
self.loadObject.modulesJSON = [NSDictionary dictionaryWithDictionary:mutableDictionary];
|
||||||
|
} else {
|
||||||
|
self.loadObject.modulesJSON = modules;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)verifyRequiredModulesLoadedForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(MVMCoreErrorObject *_Nonnull *_Nonnull)error {
|
||||||
|
|
||||||
if (page || modules.count > 0) {
|
// Check if all needed modules are loaded.
|
||||||
|
__block NSMutableArray *modulesRequired = [NSMutableArray arrayWithArray:[[MVMCoreViewControllerMappingObject sharedViewControllerMappingObject] modulesRequiredForPageType:loadObject.pageType]];
|
||||||
|
if (modulesRequired.count > 0) {
|
||||||
|
|
||||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
[[loadObject.modulesJSON allKeys] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||||
|
|
||||||
if (modules) {
|
if (modulesRequired.count == 0) {
|
||||||
if (self.loadObject.modulesJSON) {
|
*stop = YES;
|
||||||
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:self.loadObject.modulesJSON];
|
} else {
|
||||||
[mutableDictionary addEntriesFromDictionary:modules];
|
NSUInteger index = [modulesRequired indexOfObject:obj];
|
||||||
self.loadObject.modulesJSON = [NSDictionary dictionaryWithDictionary:mutableDictionary];
|
if (index != NSNotFound) {
|
||||||
} else {
|
[modulesRequired removeObjectAtIndex:index];
|
||||||
self.loadObject.modulesJSON = modules;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page) {
|
|
||||||
self.loadObject.pageJSON = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self updateUI];
|
|
||||||
[self.view setNeedsLayout];
|
|
||||||
[self.view layoutIfNeeded];
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
if (modulesRequired.count == 0) {
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Error, not all needed modules are loaded.
|
||||||
|
if (error) {
|
||||||
|
*error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] messageToLog:[modulesRequired description] code:ErrorCodeRequiredModuleNotPresent domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,7 +458,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Since we have new data, build stuff for the screen and update the ui once the screen is done laying out.
|
// Since we have new data, build stuff for the screen and update the ui once the screen is done laying out.
|
||||||
[self updateUI];
|
[self newDataBuildAndUpdate];
|
||||||
|
|
||||||
self.needToupdateUIOnScreenSizeChanges = YES;
|
self.needToupdateUIOnScreenSizeChanges = YES;
|
||||||
|
|
||||||
@ -439,10 +471,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateUI {
|
- (void)newDataBuildAndUpdate {
|
||||||
[self newDataBuildScreen];
|
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||||
[self.formValidator enableByValidation];
|
[self newDataBuildScreen];
|
||||||
self.needToUpdateUI = YES;
|
[self.formValidator enableByValidation];
|
||||||
|
self.needToUpdateUI = YES;
|
||||||
|
[self.view setNeedsLayout];
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didReceiveMemoryWarning {
|
- (void)didReceiveMemoryWarning {
|
||||||
|
|||||||
@ -64,7 +64,7 @@ import UIKit
|
|||||||
primaryButton?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
primaryButton?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?) -> CGFloat {
|
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
return 42
|
return 42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
@import MVMCore.MVMCoreViewProtocol;
|
@import MVMCore.MVMCoreViewProtocol;
|
||||||
@class MVMCoreUIDelegateObject;
|
@class MVMCoreUIDelegateObject;
|
||||||
|
@class MVMCoreErrorObject;
|
||||||
|
|
||||||
@protocol MVMCoreUIMoleculeViewProtocol <NSObject, MVMCoreViewProtocol>
|
@protocol MVMCoreUIMoleculeViewProtocol <NSObject, MVMCoreViewProtocol>
|
||||||
|
|
||||||
@ -25,11 +26,14 @@
|
|||||||
|
|
||||||
|
|
||||||
/// For the molecule list to load more efficiently.
|
/// For the molecule list to load more efficiently.
|
||||||
+ (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json;
|
+ (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
|
||||||
|
|
||||||
/// Allows the molecule to set its name for reuse. Default could be moleculeName.
|
/// Allows the molecule to set its name for reuse. Default could be moleculeName.
|
||||||
+ (nullable NSString *)nameForReuse:(nullable NSDictionary *)molecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
|
+ (nullable NSString *)nameForReuse:(nullable NSDictionary *)molecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
|
||||||
|
|
||||||
|
/// Can return the required modules
|
||||||
|
+ (nullable NSArray <NSString *>*)requiredModules:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
101
MVMCoreUI/Molecules/ModuleMolecule.swift
Normal file
101
MVMCoreUI/Molecules/ModuleMolecule.swift
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
//
|
||||||
|
// ModuleMolecule.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 6/25/19.
|
||||||
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
open class ModuleMolecule: ViewConstrainingView {
|
||||||
|
|
||||||
|
open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)?
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
molecule?.updateView(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
|
guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
|
||||||
|
// Critical error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if molecule == nil {
|
||||||
|
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: module, delegateObject: delegateObject, constrainIfNeeded: true) {
|
||||||
|
addSubview(moleculeView)
|
||||||
|
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values))
|
||||||
|
molecule = moleculeView
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
molecule?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setAsMolecule() {
|
||||||
|
super.setAsMolecule()
|
||||||
|
updateViewHorizontalDefaults = false
|
||||||
|
molecule?.setAsMolecule?()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func reset() {
|
||||||
|
super.reset()
|
||||||
|
molecule?.reset?()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override static 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
|
||||||
|
}
|
||||||
|
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
public override static 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<>"
|
||||||
|
}
|
||||||
|
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]? {
|
||||||
|
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)) {
|
||||||
|
error?.pointee = errorObject
|
||||||
|
MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let moduleName = moduleName {
|
||||||
|
return [moduleName]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||||
|
open override func useStandardConstraints() -> Bool {
|
||||||
|
return (molecule as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func alignHorizontal(_ alignment: UIStackView.Alignment) {
|
||||||
|
(molecule as? MVMCoreUIViewConstrainingProtocol)?.alignHorizontal?(alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func alignVertical(_ alignment: UIStackView.Alignment) {
|
||||||
|
(molecule as? MVMCoreUIViewConstrainingProtocol)?.alignVertical?(alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func shouldSetHorizontalMargins(_ shouldSet: Bool) {
|
||||||
|
(molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(shouldSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func shouldSetVerticalMargins(_ shouldSet: Bool) {
|
||||||
|
(molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(shouldSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -39,11 +39,15 @@ public class StackItem {
|
|||||||
public class MoleculeStackView: ViewConstrainingView {
|
public class MoleculeStackView: ViewConstrainingView {
|
||||||
var contentView: UIView = MVMCoreUICommonViewsUtility.commonView()
|
var contentView: UIView = MVMCoreUICommonViewsUtility.commonView()
|
||||||
var items: [StackItem] = []
|
var items: [StackItem] = []
|
||||||
|
var useStackSpacingBeforeFirstItem = false
|
||||||
|
|
||||||
|
private var moleculesShouldSetHorizontalMargins = true
|
||||||
|
private var moleculesShouldSetVerticalMargins = false
|
||||||
|
|
||||||
/// For setting the direction of the stack
|
/// For setting the direction of the stack
|
||||||
var axis: NSLayoutConstraint.Axis = .vertical {
|
var axis: NSLayoutConstraint.Axis = .vertical {
|
||||||
didSet {
|
didSet {
|
||||||
updateViewHorizontalDefaults = axis == .horizontal
|
moleculesShouldSetHorizontalMargins = (moleculesShouldSetHorizontalMargins && axis == .vertical)
|
||||||
if axis != oldValue {
|
if axis != oldValue {
|
||||||
restack()
|
restack()
|
||||||
}
|
}
|
||||||
@ -107,7 +111,8 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
}
|
}
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
addConstrainedView(contentView)
|
addSubview(contentView)
|
||||||
|
pinView(toSuperView: contentView)
|
||||||
contentView.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
contentView.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||||
contentView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
contentView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||||
}
|
}
|
||||||
@ -133,6 +138,22 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override func shouldSetHorizontalMargins(_ shouldSet: Bool) {
|
||||||
|
super.shouldSetHorizontalMargins(shouldSet)
|
||||||
|
moleculesShouldSetHorizontalMargins = (shouldSet && axis == .vertical)
|
||||||
|
for item in items {
|
||||||
|
(item.view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func shouldSetVerticalMargins(_ shouldSet: Bool) {
|
||||||
|
super.shouldSetVerticalMargins(shouldSet)
|
||||||
|
moleculesShouldSetVerticalMargins = false
|
||||||
|
for item in items {
|
||||||
|
(item.view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
let previousJSON = self.json
|
let previousJSON = self.json
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
@ -144,10 +165,6 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
items = self.items
|
items = self.items
|
||||||
}
|
}
|
||||||
self.items = []
|
self.items = []
|
||||||
|
|
||||||
if let colorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
|
||||||
backgroundColor = .mfGet(forHex: colorString)
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
|
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
|
||||||
return
|
return
|
||||||
@ -163,7 +180,7 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
alignVertical(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill))
|
alignVertical(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill))
|
||||||
} else {
|
} else {
|
||||||
alignHorizontal(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill))
|
alignHorizontal(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill))
|
||||||
alignVertical(.leading)
|
alignVertical(.fill)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds the molecules and sets the json.
|
// Adds the molecules and sets the json.
|
||||||
@ -171,35 +188,70 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule) {
|
if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule) {
|
||||||
var view: UIView?
|
var view: UIView?
|
||||||
if let item = items?[index] {
|
if let item = items?[index] {
|
||||||
(item.view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
|
item.update(with: map)
|
||||||
item.update(with: moleculeJSON)
|
|
||||||
view = item.view
|
view = item.view
|
||||||
|
(view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: nil)
|
||||||
addStackItem(item, lastItem: index == molecules.count - 1)
|
addStackItem(item, lastItem: index == molecules.count - 1)
|
||||||
} else if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
} else if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
||||||
view = molecule
|
view = molecule
|
||||||
addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1)
|
addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1)
|
||||||
}
|
}
|
||||||
|
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins)
|
||||||
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(axis == .vertical)
|
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins)
|
||||||
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
// This will aggregate names of molecules to make an id.
|
// This will aggregate names of molecules to make an id.
|
||||||
var name = ""
|
|
||||||
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
|
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
|
||||||
return name
|
return "stack<>"
|
||||||
}
|
}
|
||||||
|
var name = "stack<"
|
||||||
for case let item as [AnyHashable: AnyHashable] in molecules {
|
for case let item as [AnyHashable: AnyHashable] in molecules {
|
||||||
if let moleculeName = item.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule, KeyMoleculeName]) {
|
if let molecule = item.optionalDictionaryForKey(KeyMolecule), let moleculeName = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) {
|
||||||
name.append(moleculeName)
|
name.append(moleculeName + ",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
name.append(">")
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
let horizontal = json?.optionalStringForKey("axis") == "horizontal"
|
||||||
|
var estimatedHeight: CGFloat = 0
|
||||||
|
for case let item as [AnyHashable: AnyHashable] in items {
|
||||||
|
if let molecule = item.optionalDictionaryForKey(KeyMolecule) {
|
||||||
|
let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.estimatedHeight?(forRow: molecule, delegateObject: delegateObject)
|
||||||
|
if !horizontal {
|
||||||
|
// Vertical stack aggregates the items
|
||||||
|
let spacing = item.optionalCGFloatForKey("spacing") ?? (estimatedHeight != 0 ? (json?.optionalCGFloatForKey("spacing") ?? 16) : 0)
|
||||||
|
estimatedHeight += ((height ?? 0) + spacing)
|
||||||
|
} else if let height = height {
|
||||||
|
// Horizontal stack takes the tallest item.
|
||||||
|
estimatedHeight = max(estimatedHeight, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return estimatedHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||||
|
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var modules: [String] = []
|
||||||
|
for case let item as [AnyHashable: AnyHashable] in items {
|
||||||
|
if let molecule = item.optionalDictionaryForKey(KeyMolecule), let modulesForMolecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.requiredModules?(molecule, delegateObject: delegateObject, error: error) {
|
||||||
|
modules += modulesForMolecule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modules.count > 0 ? modules : nil
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Adding to stack
|
// MARK: - Adding to stack
|
||||||
/// Adds the view to the stack.
|
/// Adds the view to the stack.
|
||||||
func addView(_ view: UIView, lastItem: Bool) {
|
func addView(_ view: UIView, lastItem: Bool) {
|
||||||
@ -221,7 +273,7 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
}
|
}
|
||||||
if axis == .vertical {
|
if axis == .vertical {
|
||||||
if items.count == 0 {
|
if items.count == 0 {
|
||||||
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: spacing)
|
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : stackItem.spacing ?? 0)
|
||||||
} else if let previousView = items.last?.view {
|
} else if let previousView = items.last?.view {
|
||||||
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: true)
|
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: true)
|
||||||
}
|
}
|
||||||
@ -236,7 +288,7 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
} else {
|
} else {
|
||||||
if items.count == 0 {
|
if items.count == 0 {
|
||||||
// First horizontal item has no spacing by default unless told otherwise.
|
// First horizontal item has no spacing by default unless told otherwise.
|
||||||
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: stackItem.spacing ?? 0)
|
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : stackItem.spacing ?? 0)
|
||||||
} else if let previousView = items.last?.view {
|
} else if let previousView = items.last?.view {
|
||||||
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: false)
|
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: false)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,12 +89,7 @@ import UIKit
|
|||||||
if molecule == nil {
|
if molecule == nil {
|
||||||
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
||||||
contentView.addSubview(moleculeView)
|
contentView.addSubview(moleculeView)
|
||||||
var standardConstraints = true
|
let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
|
||||||
if let castView = moleculeView as? MVMCoreUIViewConstrainingProtocol {
|
|
||||||
standardConstraints = castView.useStandardConstraints?() ?? true
|
|
||||||
castView.shouldSetHorizontalMargins?(!standardConstraints)
|
|
||||||
castView.shouldSetVerticalMargins?(!standardConstraints)
|
|
||||||
}
|
|
||||||
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
|
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
|
||||||
if standardConstraints {
|
if standardConstraints {
|
||||||
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
|
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
|
||||||
@ -106,6 +101,12 @@ import UIKit
|
|||||||
} else {
|
} else {
|
||||||
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
|
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
if let castView = molecule as? MVMCoreUIViewConstrainingProtocol {
|
||||||
|
let standardConstraints = castView.useStandardConstraints?() ?? true
|
||||||
|
castView.shouldSetHorizontalMargins?(!standardConstraints)
|
||||||
|
castView.shouldSetVerticalMargins?(!standardConstraints)
|
||||||
|
}
|
||||||
|
|
||||||
backgroundColor = molecule?.backgroundColor
|
backgroundColor = molecule?.backgroundColor
|
||||||
|
|
||||||
// Add the caret if there is an action and it's not declared hidden.
|
// Add the caret if there is an action and it's not declared hidden.
|
||||||
@ -126,25 +127,26 @@ import UIKit
|
|||||||
molecule?.reset?()
|
molecule?.reset?()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func estimatedHeight(forRow json: [AnyHashable: Any]?) -> CGFloat {
|
public static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else {
|
||||||
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON, delegateObject: nil),
|
|
||||||
let estimatedHeightFor = theClass.estimatedHeight else {
|
|
||||||
return 80
|
return 80
|
||||||
}
|
}
|
||||||
return estimatedHeightFor(moleculeJSON)
|
return max(80, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
if let molecule = molecule?.optionalDictionaryForKey(KeyMolecule),
|
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
|
||||||
let moleculeName = molecule.optionalStringForKey(KeyMoleculeName),
|
return nil
|
||||||
let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass,
|
|
||||||
let castClass = moleculeClass as? MVMCoreUIMoleculeViewProtocol.Type,
|
|
||||||
let nameFunc = castClass.name {
|
|
||||||
return nameFunc(molecule, delegateObject)
|
|
||||||
} else {
|
|
||||||
return molecule?.optionalDictionaryForKey(KeyMolecule)?.optionalStringForKey(KeyMoleculeName)
|
|
||||||
}
|
}
|
||||||
|
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// MARK: - Arrow
|
||||||
|
|||||||
@ -95,9 +95,6 @@ public class StandardFooterView: ViewConstrainingView {
|
|||||||
|
|
||||||
open 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)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
if let colorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
|
||||||
backgroundColor = .mfGet(forHex: colorString)
|
|
||||||
}
|
|
||||||
twoButtonView.setWithJSON(json?.optionalDictionaryForKey("twoButtonView"), delegateObject: delegateObject, additionalData: additionalData)
|
twoButtonView.setWithJSON(json?.optionalDictionaryForKey("twoButtonView"), delegateObject: delegateObject, additionalData: additionalData)
|
||||||
textButton.setWithJSON(json?.optionalDictionaryForKey("textButton"), delegateObject: delegateObject, additionalData: additionalData)
|
textButton.setWithJSON(json?.optionalDictionaryForKey("textButton"), delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
@ -106,4 +103,8 @@ public class StandardFooterView: ViewConstrainingView {
|
|||||||
twoButtonView.reset()
|
twoButtonView.reset()
|
||||||
textButton.reset()
|
textButton.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
return 42
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,20 +111,9 @@ public class StandardHeaderView: ViewConstrainingView {
|
|||||||
separatorView?.rightPin?.constant = constant
|
separatorView?.rightPin?.constant = constant
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func reset() {
|
|
||||||
backgroundColor = .clear
|
|
||||||
headlineLabel.styleH2(true)
|
|
||||||
messageLabel.styleB2(true)
|
|
||||||
separatorView?.setAsHeavy()
|
|
||||||
separatorView?.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
open 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)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
if let colorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
|
||||||
backgroundColor = .mfGet(forHex: colorString)
|
|
||||||
}
|
|
||||||
if let colorString = json?.optionalStringForKey("contentColor") {
|
if let colorString = json?.optionalStringForKey("contentColor") {
|
||||||
let color = UIColor.mfGet(forHex: colorString)
|
let color = UIColor.mfGet(forHex: colorString)
|
||||||
headlineLabel.textColor = color
|
headlineLabel.textColor = color
|
||||||
@ -146,4 +135,16 @@ public class StandardHeaderView: ViewConstrainingView {
|
|||||||
bottomPin?.constant = PaddingDefaultVerticalSpacing
|
bottomPin?.constant = PaddingDefaultVerticalSpacing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open override func reset() {
|
||||||
|
backgroundColor = .clear
|
||||||
|
headlineLabel.styleH2(true)
|
||||||
|
messageLabel.styleB2(true)
|
||||||
|
separatorView?.setAsHeavy()
|
||||||
|
separatorView?.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
return 121
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,5 +83,9 @@ import UIKit
|
|||||||
public override func alignment() -> UIStackView.Alignment {
|
public override func alignment() -> UIStackView.Alignment {
|
||||||
return UIStackView.Alignment.leading
|
return UIStackView.Alignment.leading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
return MVMCoreUISwitch.getHeight()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,11 +41,8 @@ import UIKit
|
|||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
open 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)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
let primaryButtonMap = json?.optionalDictionaryForKey("primaryButton")
|
||||||
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
|
let secondaryButtonMap = json?.optionalDictionaryForKey("secondaryButton")
|
||||||
}
|
|
||||||
let primaryButtonMap = json?.optionalDictionaryForKey(KeyPrimaryButton)
|
|
||||||
let secondaryButtonMap = json?.optionalDictionaryForKey(KeySecondaryButton)
|
|
||||||
set(primaryButtonJSON: primaryButtonMap, secondaryButtonJSON: secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData)
|
set(primaryButtonJSON: primaryButtonMap, secondaryButtonJSON: secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,22 +21,19 @@
|
|||||||
+ (nullable instancetype)sharedMappingObject;
|
+ (nullable instancetype)sharedMappingObject;
|
||||||
|
|
||||||
/// Returns the molecule class.
|
/// Returns the molecule class.
|
||||||
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
|
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json;
|
||||||
|
|
||||||
#pragma mark - Molecule Creation
|
#pragma mark - Molecule Creation
|
||||||
|
|
||||||
/// Creates the molecule for the given name.
|
/// Creates the molecule for the molecule json.
|
||||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForName:(nonnull NSString *)name;
|
|
||||||
|
|
||||||
/// Creates the molecule for the molecule json. Takes into account moduleMolecule as well.
|
|
||||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
|
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)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.
|
/// Creates the molecule for the molecule json. Also checks if the molecule needs to be constrained for a stack/list style situation.
|
||||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded;
|
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded;
|
||||||
|
|
||||||
#pragma mark - ModuleMolecule Helpers
|
#pragma mark - Convenience
|
||||||
|
|
||||||
/// If the molecule is a module molecule, will get the map for the molecule to load from a module. Otherwise nil.
|
+ (nullable NSArray <NSString *>*)getRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error;
|
||||||
+ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error;
|
+ (void)addRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject moduleList:(nullable NSMutableArray <NSDictionary *>*)moduleList errorList:(nullable NSMutableArray <MVMCoreErrorObject *>*)errorList;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
@import MVMCore.MVMCoreActionUtility;
|
@import MVMCore.MVMCoreActionUtility;
|
||||||
@import MVMCore.NSDictionary_MFConvenience;
|
@import MVMCore.NSDictionary_MFConvenience;
|
||||||
@import MVMCore.MVMCoreLoadObject;
|
@import MVMCore.MVMCoreLoadObject;
|
||||||
|
@import MVMCore.MVMCoreErrorObject;
|
||||||
#import "MVMCoreUIObject.h"
|
#import "MVMCoreUIObject.h"
|
||||||
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
||||||
#import "MFTextField.h"
|
#import "MFTextField.h"
|
||||||
@ -35,6 +36,7 @@
|
|||||||
@"caretView": CaretView.class,
|
@"caretView": CaretView.class,
|
||||||
@"caretButton": CaretButton.class,
|
@"caretButton": CaretButton.class,
|
||||||
@"textField" : MFTextField.class,
|
@"textField" : MFTextField.class,
|
||||||
|
@"digitTextField" : MFDigitTextField.class,
|
||||||
@"checkbox" : MVMCoreUICheckBox.class,
|
@"checkbox" : MVMCoreUICheckBox.class,
|
||||||
@"progressBarWithLabel" : ProgressBarWithLabel.class,
|
@"progressBarWithLabel" : ProgressBarWithLabel.class,
|
||||||
@"progressBar": ProgressBar.class,
|
@"progressBar": ProgressBar.class,
|
||||||
@ -44,7 +46,9 @@
|
|||||||
@"switchLineItem": SwitchLineItem.class,
|
@"switchLineItem": SwitchLineItem.class,
|
||||||
@"switch": Switch.class,
|
@"switch": Switch.class,
|
||||||
@"leftRightLabelView": LeftRightLabelView.class,
|
@"leftRightLabelView": LeftRightLabelView.class,
|
||||||
@"standardListItemWithImage": StandardListItemWithImage.class
|
@"standardListItemWithImage": StandardListItemWithImage.class,
|
||||||
|
@"image": MFLoadImageView.class,
|
||||||
|
@"moduleMolecule": ModuleMolecule.class
|
||||||
} mutableCopy];
|
} mutableCopy];
|
||||||
});
|
});
|
||||||
return mapping;
|
return mapping;
|
||||||
@ -55,9 +59,8 @@
|
|||||||
return [MVMCoreActionUtility initializerClassCheck:[MVMCoreUIObject sharedInstance].moleculeMap classToVerify:self];
|
return [MVMCoreActionUtility initializerClassCheck:[MVMCoreUIObject sharedInstance].moleculeMap classToVerify:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject {
|
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json {
|
||||||
NSDictionary *moleculeJSON = [MVMCoreUIMoleculeMappingObject getMoleculeMapForModuleMolecule:json delegateObject:delegateObject error:nil] ?: json;
|
NSString *moleculeName = [json string:KeyMoleculeName];
|
||||||
NSString *moleculeName = [moleculeJSON string:KeyMoleculeName];
|
|
||||||
if (moleculeName) {
|
if (moleculeName) {
|
||||||
return [self.moleculeMapping objectForKey:moleculeName];
|
return [self.moleculeMapping objectForKey:moleculeName];
|
||||||
}
|
}
|
||||||
@ -83,36 +86,41 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded {
|
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded {
|
||||||
NSDictionary *moleculeJSON = [MVMCoreUIMoleculeMappingObject getMoleculeMapForModuleMolecule:json delegateObject:delegateObject error:nil] ?: json;
|
NSString *moleculeName = [json string:KeyMoleculeName];
|
||||||
NSString *moleculeName = [moleculeJSON string:KeyMoleculeName];
|
|
||||||
if (!moleculeName) {
|
if (!moleculeName) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [self createMoleculeForName:moleculeName];
|
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [self createMoleculeForName:moleculeName];
|
||||||
|
|
||||||
// Check if we need to constrain this view.
|
// Check if we need to constrain this view.
|
||||||
UIView <MVMCoreUIViewConstrainingProtocol> *castMolecule = [molecule conformsToProtocol:@protocol(MVMCoreUIViewConstrainingProtocol)] ? (UIView <MVMCoreUIViewConstrainingProtocol> *)molecule : nil;
|
UIView <MVMCoreUIViewConstrainingProtocol> *castMolecule = [molecule conformsToProtocol:@protocol(MVMCoreUIViewConstrainingProtocol)] ? (UIView <MVMCoreUIViewConstrainingProtocol> *)molecule : nil;
|
||||||
if (constrainIfNeeded && [castMolecule respondsToSelector:@selector(needsToBeConstrained)] && [castMolecule needsToBeConstrained]) {
|
if (constrainIfNeeded && [castMolecule respondsToSelector:@selector(needsToBeConstrained)] && [castMolecule needsToBeConstrained]) {
|
||||||
molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[castMolecule respondsToSelector:@selector(alignment)] ? [castMolecule alignment] : UIStackViewAlignmentFill];
|
molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[castMolecule respondsToSelector:@selector(alignment)] ? [castMolecule alignment] : UIStackViewAlignmentFill];
|
||||||
}
|
}
|
||||||
[molecule setWithJSON:moleculeJSON delegateObject:delegateObject additionalData:nil];
|
[molecule setWithJSON:json delegateObject:delegateObject additionalData:nil];
|
||||||
return molecule;
|
return molecule;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - ModuleMolecule Helpers
|
#pragma mark - Convenience
|
||||||
|
|
||||||
+ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
|
+ (nullable NSArray <NSString *>*)getRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
|
||||||
NSString *moleculeName = [moduleMolecule string:KeyMoleculeName];
|
Class <MVMCoreUIMoleculeViewProtocol>theClass = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] getMoleculeClassWithJSON:json];
|
||||||
if ([moleculeName isEqualToString:@"moduleMolecule"]) {
|
if ([theClass respondsToSelector:@selector(requiredModules:delegateObject:error:)]) {
|
||||||
NSString *moduleName = [moduleMolecule string:@"moduleName"];
|
return [theClass requiredModules:json delegateObject:delegateObject error:error];
|
||||||
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 {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)addRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject moduleList:(nullable NSMutableArray <NSDictionary *>*)moduleList errorList:(nullable NSMutableArray <MVMCoreErrorObject *>*)errorList {
|
||||||
|
MVMCoreErrorObject *error = nil;
|
||||||
|
NSArray *modules = [self getRequiredModulesForJSON:json delegateObject:delegateObject error:&error];
|
||||||
|
if (modules) {
|
||||||
|
[moduleList addObjectsFromArray:modules];
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
[errorList addObject:error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -21,6 +21,9 @@
|
|||||||
/// Can be used to override any standard constraints that may be added.
|
/// Can be used to override any standard constraints that may be added.
|
||||||
- (BOOL)useStandardConstraints;
|
- (BOOL)useStandardConstraints;
|
||||||
|
|
||||||
|
/// Determines if the constraining view will copy the background color of the delegate.
|
||||||
|
- (BOOL)copyBackgroundColor;
|
||||||
|
|
||||||
/// Will align if it can.
|
/// Will align if it can.
|
||||||
- (void)alignHorizontal:(UIStackViewAlignment)alignment;
|
- (void)alignHorizontal:(UIStackViewAlignment)alignment;
|
||||||
- (void)alignVertical:(UIStackViewAlignment)alignment;
|
- (void)alignVertical:(UIStackViewAlignment)alignment;
|
||||||
|
|||||||
@ -1,47 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,22 +9,23 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
open class MoleculeListTemplate: ThreeLayerTableViewController {
|
open class MoleculeListTemplate: ThreeLayerTableViewController {
|
||||||
var molecules: [(molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)]?
|
var moleculesInfo: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]?
|
||||||
|
var observer: NSKeyValueObservation?
|
||||||
|
|
||||||
open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
|
open override var loadObject: MVMCoreLoadObject? {
|
||||||
var shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error)
|
didSet {
|
||||||
guard shouldFinish else {
|
if loadObject != oldValue {
|
||||||
return shouldFinish
|
updateRequiredModules()
|
||||||
|
observer?.invalidate()
|
||||||
|
if let newObject = loadObject {
|
||||||
|
observer = newObject.observe(\MVMCoreLoadObject.pageJSON, options: [.old, .new]) { [weak self] (object, change) in
|
||||||
|
self?.updateRequiredModules()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
open override func viewForTop() -> UIView {
|
||||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"),
|
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"),
|
||||||
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
|
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
|
||||||
@ -43,41 +44,36 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
|
|
||||||
open override func newDataBuildScreen() {
|
open override func newDataBuildScreen() {
|
||||||
super.newDataBuildScreen()
|
super.newDataBuildScreen()
|
||||||
_ = setupMoleculeList()
|
setup()
|
||||||
registerWithTable()
|
registerWithTable()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - table
|
// MARK: - table
|
||||||
open override func registerWithTable() {
|
open override func registerWithTable() {
|
||||||
super.registerWithTable()
|
super.registerWithTable()
|
||||||
guard let molecules = molecules else {
|
guard let moleculesInfo = moleculesInfo else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for molecule in molecules {
|
for moleculeInfo in moleculesInfo {
|
||||||
if let moleculeInfo = getMoleculeInfo(with: molecule), let moleculeToRegister = moleculeInfo.name {
|
tableView?.register(moleculeInfo.class, forCellReuseIdentifier: moleculeInfo.identifier)
|
||||||
tableView?.register(moleculeInfo.class, forCellReuseIdentifier: moleculeToRegister)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||||
guard let molecule = molecules?[indexPath.row],
|
guard let moleculeInfo = moleculesInfo?[indexPath.row],
|
||||||
let moleculeInfo = getMoleculeInfo(with: molecule),
|
let estimatedHeight = moleculeInfo.class.estimatedHeight?(forRow: moleculeInfo.molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) else {
|
||||||
let estimatedHeight = moleculeInfo.class.estimatedHeight else {
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return estimatedHeight(molecule.molecule)
|
return estimatedHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return molecules?.count ?? 0
|
return moleculesInfo?.count ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
guard let molecule = molecules?[indexPath.row],
|
guard let moleculeInfo = moleculesInfo?[indexPath.row],
|
||||||
let moleculeInfo = getMoleculeInfo(with: molecule),
|
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeInfo.identifier) else {
|
||||||
let moleculeName = moleculeInfo.name,
|
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeName) else {
|
|
||||||
return UITableViewCell()
|
return UITableViewCell()
|
||||||
}
|
}
|
||||||
let delegate = delegateObject() as? MVMCoreUIDelegateObject
|
let delegate = delegateObject() as? MVMCoreUIDelegateObject
|
||||||
@ -86,7 +82,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
}
|
}
|
||||||
if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol {
|
if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol {
|
||||||
protocolCell.reset?()
|
protocolCell.reset?()
|
||||||
protocolCell.setWithJSON(molecule.molecule, delegateObject: delegate, additionalData: nil)
|
protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: delegate, additionalData: nil)
|
||||||
protocolCell.updateView(tableView.bounds.width)
|
protocolCell.updateView(tableView.bounds.width)
|
||||||
}
|
}
|
||||||
return cell
|
return cell
|
||||||
@ -107,79 +103,64 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override func modulesToListenFor() -> [Any]? {
|
open override func modulesToListenFor() -> [Any]? {
|
||||||
// Get all of the molecules that need modules.
|
return loadObject?.requestParameters?.modules
|
||||||
return modulesNeeded()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Module Molecule Handling
|
// MARK: - Convenience
|
||||||
/// Returns the (name, class) of the molecule for the given map.
|
/// Returns the (identifier, class) of the molecule for the given map.
|
||||||
func getMoleculeInfo(with molecule: (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)) -> (name: String?, class: AnyClass)? {
|
func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? {
|
||||||
guard let map = molecule.molecule, let moleculeName = map.optionalStringForKey(KeyMoleculeName), let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass else {
|
guard let molecule = molecule,
|
||||||
|
let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule),
|
||||||
|
let moleculeName = moleculeClass.name?(forReuse: molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if let moleculeClass = moleculeClass as? MVMCoreUIMoleculeViewProtocol.Type, let moleculeNameFunc = moleculeClass.name {
|
return (moleculeName, moleculeClass, molecule)
|
||||||
return (moleculeNameFunc(map, delegateObject() as? MVMCoreUIDelegateObject), moleculeClass)
|
|
||||||
} else {
|
|
||||||
return (moleculeName, moleculeClass)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up the molecule list and ensures no errors loading all content.
|
/// Sets up the molecule list and ensures no errors loading all content.
|
||||||
func setupMoleculeList() -> [MVMCoreErrorObject]? {
|
func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? {
|
||||||
var errors: [MVMCoreErrorObject] = []
|
var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = []
|
||||||
let delegate = delegateObject() as? MVMCoreUIDelegateObject
|
|
||||||
var moleculeList: [(molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)] = []
|
|
||||||
if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] {
|
if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] {
|
||||||
for molecule in molecules {
|
for molecule in molecules {
|
||||||
if let object = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: molecule, delegateObject: delegate) {
|
if let info = getMoleculeInfo(with: molecule) {
|
||||||
if let error = object.error {
|
moleculeList.append(info)
|
||||||
errors.append(error)
|
|
||||||
} else {
|
|
||||||
moleculeList.append(object)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
molecules = moleculeList
|
return moleculeList.count > 0 ? moleculeList : nil
|
||||||
return errors.count > 0 ? errors : nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up the header, footer, molecule list and ensures no errors loading all content.
|
/// Sets up the header, footer, molecule list and ensures no errors loading all content.
|
||||||
func setup() -> [MVMCoreErrorObject]? {
|
func setup() {
|
||||||
var errors: [MVMCoreErrorObject] = []
|
var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = []
|
||||||
let delegate = delegateObject() as? MVMCoreUIDelegateObject
|
if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] {
|
||||||
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 {
|
for molecule in molecules {
|
||||||
MoleculeListTemplate.addToModuleList(with: molecule, moduleNames: &modules)
|
if let info = getMoleculeInfo(with: molecule) {
|
||||||
|
moleculeList.append(info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (modules.count > 0 ? modules : nil)
|
moleculesInfo = moleculeList
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map.
|
||||||
|
open func updateRequiredModules() {
|
||||||
|
if let requiredModules = requiredModules(), let pageType = pageType {
|
||||||
|
MVMCoreViewControllerMappingObject.shared()?.addRequiredModules(toMapping: requiredModules, forPageType: pageType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets modules required by the loadObject.pageJSON.
|
||||||
|
open func requiredModules() -> [Any]? {
|
||||||
|
let modules: NSMutableArray = []
|
||||||
|
let delegate = delegateObject() as? MVMCoreUIDelegateObject
|
||||||
|
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate, moduleList: modules, errorList: nil)
|
||||||
|
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate, moduleList: modules, errorList: nil)
|
||||||
|
if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] {
|
||||||
|
for molecule in molecules {
|
||||||
|
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: molecule, delegateObject: delegate, moduleList: modules, errorList: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modules as? [Any]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,15 +9,20 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public class MoleculeStackTemplate: ThreeLayerViewController {
|
public class MoleculeStackTemplate: ThreeLayerViewController {
|
||||||
|
var observer: NSKeyValueObservation?
|
||||||
|
|
||||||
public override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
|
open override var loadObject: MVMCoreLoadObject? {
|
||||||
var shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error)
|
didSet {
|
||||||
if shouldFinish, let firstError = modulesNeeded().errors?.first {
|
if loadObject != oldValue {
|
||||||
// Don't continue if there was an error loading needed modules.
|
updateRequiredModules()
|
||||||
error.pointee = firstError
|
observer?.invalidate()
|
||||||
shouldFinish = false
|
if let newObject = loadObject {
|
||||||
|
observer = newObject.observe(\MVMCoreLoadObject.pageJSON, options: [.old, .new]) { [weak self] (object, change) in
|
||||||
|
self?.updateRequiredModules()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return shouldFinish
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func spaceBetweenTopAndMiddle() -> CGFloat? {
|
public override func spaceBetweenTopAndMiddle() -> CGFloat? {
|
||||||
@ -35,7 +40,10 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
|
|||||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else {
|
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return MoleculeStackView(withJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil)
|
let stack = MoleculeStackView(frame: .zero)
|
||||||
|
stack.useStackSpacingBeforeFirstItem = true
|
||||||
|
stack.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil)
|
||||||
|
return stack
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func viewForBottom() -> UIView? {
|
override public func viewForBottom() -> UIView? {
|
||||||
@ -54,23 +62,23 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override func modulesToListenFor() -> [Any]? {
|
public override func modulesToListenFor() -> [Any]? {
|
||||||
// Get all of the molecules that need modules.
|
return loadObject?.requestParameters?.modules
|
||||||
return modulesNeeded().modules
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Module Molecule Handling
|
/// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map.
|
||||||
func modulesNeeded() -> (modules: [String]?, errors: [MVMCoreErrorObject]?) {
|
open func updateRequiredModules() {
|
||||||
var modules: [String]? = []
|
if let requiredModules = requiredModules(), let pageType = pageType {
|
||||||
var errors: [MVMCoreErrorObject]? = []
|
MVMCoreViewControllerMappingObject.shared()?.addRequiredModules(toMapping: requiredModules, forPageType: pageType)
|
||||||
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)
|
}
|
||||||
|
|
||||||
|
/// Gets modules required by the loadObject.pageJSON.
|
||||||
|
open func requiredModules() -> [Any]? {
|
||||||
|
let modules: NSMutableArray = []
|
||||||
|
let delegate = delegateObject() as? MVMCoreUIDelegateObject
|
||||||
|
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate, moduleList: modules, errorList: nil)
|
||||||
|
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate, moduleList: modules, errorList: nil)
|
||||||
|
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack"), delegateObject: delegate, moduleList: modules, errorList: nil)
|
||||||
|
return modules as? [Any]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user