From 0f458d21a3733efb3c62fd44c72b9e2309068323 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 15 May 2019 11:16:08 -0400 Subject: [PATCH] module molecule --- .../MVMCoreUIMoleculeMappingObject.h | 19 ++++++-- .../MVMCoreUIMoleculeMappingObject.m | 42 +++++++++++++++++ .../Templates/MoleculeStackTemplate.swift | 47 +++++++++++++++++++ MVMCoreUI/Utility/MVMCoreUIConstants.h | 7 +++ 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h index 43a113c9..79534f20 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h @@ -9,20 +9,31 @@ #import #import @class DelegateObject; +@class MVMCoreLoadObject; +@class MVMCoreErrorObject; @interface MVMCoreUIMoleculeMappingObject : NSObject -// Maps molecule name to class. +/// Maps molecule name to class. @property (nullable, strong, nonatomic) NSMutableDictionary *moleculeMapping; -// Returns the shared instance +/// Returns the shared instance + (nullable instancetype)sharedMappingObject; -// Returns the molecule for the given name. +/// Returns the molecule for the given name. - (nullable UIView *)getMoleculeForName:(nonnull NSString *)name; - (nullable UIView *)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject; -// Similar to above but also checks if the molecule needs to be constrained for a stack. +/// Returns the molecule for the json. Also checks if the molecule needs to be constrained for a stack. - (nullable UIView *)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject; +/// Returns the molecule for the json. Checks if the molecule needs to be constrained for a stack. Load object may be used if the molecule needs to be loaded from the page or module map. +- (nullable UIView *)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject loadObject:(nullable MVMCoreLoadObject *)loadObject; + +#pragma mark - Helpers + +/// Gets the molecule from the passed in module map. ++ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule moduleMap:(nullable NSDictionary *)moduleMap error:(MVMCoreErrorObject *_Nullable *_Nullable)error; ++ (nullable NSString *)getMoleculeNameForModuleMolecule:(nullable NSDictionary *)moduleMolecule moduleMap:(nullable NSDictionary *)moduleMap error:(MVMCoreErrorObject *_Nullable *_Nullable)error; + @end diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index e1101191..58586bb5 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -9,6 +9,7 @@ #import "MVMCoreUIMoleculeMappingObject.h" @import MVMCore.MVMCoreActionUtility; @import MVMCore.NSDictionary_MFConvenience; +@import MVMCore.MVMCoreLoadObject; #import "MVMCoreUIObject.h" #import #import "MFTextField.h" @@ -80,4 +81,45 @@ return molecule; } +- (nullable UIView *)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject loadObject:(nullable MVMCoreLoadObject *)loadObject { + NSString *moleculeName = [json string:KeyMoleculeName]; + if (!moleculeName) { + return nil; + } else if ([moleculeName isEqualToString:@"moduleMolecule"]) { + NSString *moduleName = [json string:@"moduleName"]; + if (moduleName) { + NSDictionary *newJSON = [loadObject.modulesJSON dict:moduleName]; + if (newJSON) { + json = newJSON; + } + } + } + UIView *molecule = [self getMoleculeForName:moleculeName]; + if ([molecule respondsToSelector:@selector(needsToBeConstrained)] && [molecule needsToBeConstrained]) { + molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[molecule respondsToSelector:@selector(moleculeAlignment)] ? [molecule moleculeAlignment] : UIStackViewAlignmentFill]; + } + [molecule setWithJSON:json delegateObject:delegateObject additionalData:nil]; + return molecule; +} + +#pragma mark - Helpers + ++ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule moduleMap:(nullable NSDictionary *)moduleMap error:(MVMCoreErrorObject *_Nullable *_Nullable)error { + NSString *moleculeName = [moduleMolecule string:KeyMoleculeName]; + if ([moleculeName isEqualToString:@"moduleMolecule"]) { + NSString *moduleName = [moduleMolecule string:@"moduleName"]; + NSDictionary *module = moduleName ? [moduleMap dict:moduleName] : nil; + if (!module && error) { + *error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeModuleMolecule domain:ErrorDomainNative location:NSStringFromClass(self)]; + } + return module; + } else { + return nil; + } +} + ++ (nullable NSString *)getMoleculeNameForModuleMolecule:(nullable NSDictionary *)moduleMolecule moduleMap:(nullable NSDictionary *)moduleMap error:(MVMCoreErrorObject *_Nullable *_Nullable)error { + return [[self getMoleculeMapForModuleMolecule:moduleMolecule moduleMap:moduleMap error:error] string:KeyMoleculeName]; +} + @end diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index 51b3ed7f..10a291d7 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -10,6 +10,15 @@ import UIKit public class MoleculeStackTemplate: ThreeLayerViewController { + public override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { + var shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error) + if shouldFinish, let firstError = modulesNeeded().errors?.first { + // Don't continue if there was an error loading needed modules. + error.pointee = firstError + shouldFinish = false + } + return shouldFinish + } public override func spaceBetweenTopAndMiddle() -> CGFloat? { return 0 @@ -35,4 +44,42 @@ public class MoleculeStackTemplate: ThreeLayerViewController { } return molecule } + + // MARK: - cache handling + public override func pageTypesToListenFor() -> [Any]? { + guard let pageType = self.pageType else { + return super.pageTypesToListenFor() + } + return [pageType] + } + + public override func modulesToListenFor() -> [Any]? { + // Get all of the molecules that need modules. + return modulesNeeded().modules + } + + // MARK: - Module Molecule Handling + func addModule(for moduleMolecule: [AnyHashable: Any]?, modules: inout [String], errors: inout [MVMCoreErrorObject]) { + var error: MVMCoreErrorObject? + if let moleculeName = MVMCoreUIMoleculeMappingObject.getMoleculeName(forModuleMolecule: moduleMolecule, moduleMap: loadObject?.modulesJSON, error: &error) { + modules.append(moleculeName) + if let errorObject = error { + MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject) + errors.append(errorObject) + } + } + } + + func modulesNeeded() -> (modules: [String]?, errors: [MVMCoreErrorObject]?) { + var modules: [String] = [] + var errors: [MVMCoreErrorObject] = [] + addModule(for: loadObject?.pageJSON?.optionalDictionaryForKey("header"), modules: &modules, errors: &errors) + addModule(for: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), modules: &modules, errors: &errors) + if let molecules = loadObject?.pageJSON?.optionalArrayForChainOfKeysOrIndexes(["moleculeStack","molecules"]) as? [[AnyHashable: Any]] { + for molecule in molecules { + addModule(for: molecule, modules: &modules, errors: &errors) + } + } + return (modules.count > 0 ? modules : nil, errors.count > 0 ? errors : nil) + } } diff --git a/MVMCoreUI/Utility/MVMCoreUIConstants.h b/MVMCoreUI/Utility/MVMCoreUIConstants.h index 189c2c49..6a3f930c 100644 --- a/MVMCoreUI/Utility/MVMCoreUIConstants.h +++ b/MVMCoreUI/Utility/MVMCoreUIConstants.h @@ -68,3 +68,10 @@ extern BOOL DisableAnimations; // Hand Scroll Key extern NSString * const KeyHandScrollAnimation; extern NSString * const KeyHandScroll; + +#pragma mark - Error Codes + +// Native Error Codes (Add new ones to bottom, don't change order!) +typedef NS_ENUM(NSInteger, CoreUIErrorCode) { + ErrorCodeModuleMolecule = 100 +};