Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/action_modernize

This commit is contained in:
Scott Pfeil 2022-07-18 19:01:01 -04:00
commit 4f2fa7962a
31 changed files with 191 additions and 149 deletions

View File

@ -129,6 +129,8 @@
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */; }; 187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */; };
1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */; }; 1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */; };
1D6D258926899B0C00DEBB08 /* ImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258726899B0B00DEBB08 /* ImageButton.swift */; }; 1D6D258926899B0C00DEBB08 /* ImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258726899B0B00DEBB08 /* ImageButton.swift */; };
27559EFC27D691D3000836C1 /* ViewMaskingProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27559EFB27D691D3000836C1 /* ViewMaskingProtocol.swift */; };
27577DCD286CA959001EC47E /* MoleculeMaskingProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27577DCC286CA959001EC47E /* MoleculeMaskingProtocol.swift */; };
279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */; }; 279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */; };
27F6B08826051831008529AA /* MoleculeTreeTraversalProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */; }; 27F6B08826051831008529AA /* MoleculeTreeTraversalProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */; };
27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */; }; 27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */; };
@ -727,6 +729,8 @@
187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; }; 187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; };
1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButtonModel.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift; sourceTree = SOURCE_ROOT; }; 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButtonModel.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift; sourceTree = SOURCE_ROOT; };
1D6D258726899B0B00DEBB08 /* ImageButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButton.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift; sourceTree = SOURCE_ROOT; }; 1D6D258726899B0B00DEBB08 /* ImageButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButton.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift; sourceTree = SOURCE_ROOT; };
27559EFB27D691D3000836C1 /* ViewMaskingProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewMaskingProtocol.swift; sourceTree = "<group>"; };
27577DCC286CA959001EC47E /* MoleculeMaskingProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeMaskingProtocol.swift; sourceTree = "<group>"; };
279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelAdapter.swift; sourceTree = "<group>"; }; 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelAdapter.swift; sourceTree = "<group>"; };
27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTreeTraversalProtocol.swift; sourceTree = "<group>"; }; 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTreeTraversalProtocol.swift; sourceTree = "<group>"; };
27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentMoleculeModelProtocol.swift; sourceTree = "<group>"; }; 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentMoleculeModelProtocol.swift; sourceTree = "<group>"; };
@ -1234,6 +1238,7 @@
D2509ED02472ED9B001BFB9D /* NavigationItemModelProtocol.swift */, D2509ED02472ED9B001BFB9D /* NavigationItemModelProtocol.swift */,
D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */, D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */,
27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */, 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */,
27577DCC286CA959001EC47E /* MoleculeMaskingProtocol.swift */,
); );
path = ModelProtocols; path = ModelProtocols;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2443,6 +2448,7 @@
D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */, D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */,
D2B9D0E3265EEE9D0084735C /* MoleculeListProtocol.swift */, D2B9D0E3265EEE9D0084735C /* MoleculeListProtocol.swift */,
011B58EE23A2AA850085F53C /* ModelProtocols */, 011B58EE23A2AA850085F53C /* ModelProtocols */,
27559EFB27D691D3000836C1 /* ViewMaskingProtocol.swift */,
); );
path = Protocols; path = Protocols;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2915,6 +2921,7 @@
D23EA800247EBD6C00D60C34 /* LabelBarButtonItem.swift in Sources */, D23EA800247EBD6C00D60C34 /* LabelBarButtonItem.swift in Sources */,
01EB368F23609801006832FA /* LabelModel.swift in Sources */, 01EB368F23609801006832FA /* LabelModel.swift in Sources */,
0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */, 0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */,
27559EFC27D691D3000836C1 /* ViewMaskingProtocol.swift in Sources */,
AA1EC59924373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift in Sources */, AA1EC59924373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift in Sources */,
AA37CBD52519072F0027344C /* Stars.swift in Sources */, AA37CBD52519072F0027344C /* Stars.swift in Sources */,
942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */, 942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */,
@ -3095,6 +3102,7 @@
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */, D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */, EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */,
011D95892404249B000E3791 /* FormHolderModelProtocol.swift in Sources */, 011D95892404249B000E3791 /* FormHolderModelProtocol.swift in Sources */,
27577DCD286CA959001EC47E /* MoleculeMaskingProtocol.swift in Sources */,
BB54C5202434D92F0038326C /* ListRightVariableButtonAllTextAndLinks.swift in Sources */, BB54C5202434D92F0038326C /* ListRightVariableButtonAllTextAndLinks.swift in Sources */,
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */, 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */, 013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */,

View File

@ -62,11 +62,4 @@ typedef void (^TextFieldErrorHandler)(NSArray * _Nonnull fieldErrors);
// Will show this alert in it's appropriate type style. // Will show this alert in it's appropriate type style.
- (void)showAlert; - (void)showAlert;
#pragma mark - Deprecated
// Creates an alert object for an error with the passed in load object response info
+ (nullable instancetype)alertObjectForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error actionDelegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)actionDelegate __deprecated;
+ (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)actionDelegate __deprecated;
+ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate error:(MVMCoreErrorObject *_Nullable *_Nullable)error __deprecated;
@end @end

View File

@ -195,113 +195,4 @@
} }
} }
#pragma mark - Deprecated
+ (nullable instancetype)alertObjectForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error actionDelegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)actionDelegate {
MVMCoreAlertObject *alert = nil;
if (!error || [ErrorDomainServer isEqualToString:error.domain]) {
alert = [MVMCoreAlertObject alertObjectForPageType:loadObject.pageType responseInfo:loadObject.responseInfoMap additionalData:loadObject.dataForPage actionDelegate:actionDelegate];
} else {
alert = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO];
}
// only if actions are empty, then go inside and set OK as default action
if (alert.type == MFAlertTypePopup && alert.actions.count == 0) {
alert.defaultAction = YES;
alert.actions = @[[UIAlertAction actionWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedOK] style:UIAlertActionStyleDefault handler:nil]];
}
return alert;
}
+ (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)actionDelegate {
__block MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init];
alert.title = [responseInfo string:KeyErrorHeading] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle];
alert.message = [responseInfo string:KeyUserMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
NSString *messageStyle = [responseInfo stringForKey:KeyMessageStyle];
if ([ValueTypeFieldErrors isEqualToString:[responseInfo string:KeyType]]) {
// field errors.
alert.type = MFAlertTypeField;
alert.fieldErrors = [responseInfo array:ValueTypeFieldErrors];
} else {
// Check for top alert (persistent or regular).
if ([messageStyle isEqualToString:ValueMessageStyleTopPersistent] || [messageStyle isEqualToString:ValueMessageStyleTop]) {
alert.topAlertObject = [[MVMCoreTopAlertObject alloc] initWithResponseInfo:responseInfo];
if ([actionDelegate conformsToProtocol:@protocol(MVMCoreTopAlertDelegateProtocol)]) {
alert.topAlertObject.delegate = (NSObject <MVMCoreTopAlertDelegateProtocol> *)actionDelegate;
}
alert.topAlertObject.pageType = pageType;
alert.type = MFAlertTypeTop;
} else if ([messageStyle isEqualToString:ValueMessageStylePopup]) {
// Perform a popup.
alert.type = MFAlertTypePopup;
alert.alertStyle = UIAlertControllerStyleAlert;
// Check if we have a popup driven by page object (otherwise by default it will just use response info title message with an OK button).
NSString *pageTypeForPopup = [responseInfo stringForKey:@"popupPageType"];
[[MVMCoreCache sharedCache] fetchJSONForPageType:pageTypeForPopup queue:nil waitUntilFinished:YES completionHandler:^(NSDictionary * _Nullable jsonDictionary) {
MVMCoreErrorObject *error = nil;
MVMCoreAlertObject *popupAlert = [MVMCoreAlertObject alertObjectWithPage:jsonDictionary isGreedy:NO additionalData:additionalData delegate:actionDelegate error:&error];
if (error) {
// Error, popup page not found for page type.
popupAlert = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO];
}
if (popupAlert) {
alert = popupAlert;
}
}];
} else if (messageStyle.length == 0 && pageType) {
// No message style!
alert.type = MFAlertTypeNone;
} else {
// Default to popup
alert.type = MFAlertTypePopup;
alert.alertStyle = UIAlertControllerStyleAlert;
}
}
if ([actionDelegate conformsToProtocol:@protocol(MVMCoreAlertDelegateProtocol)]) {
alert.alertDelegate = (NSObject <MVMCoreAlertDelegateProtocol> *)actionDelegate;
}
return alert;
}
+ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init];
alert.title = [page string:KeyTitle] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle];
alert.pageJson = page;
alert.message = [page string:KeyMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
alert.isGreedy = isGreedy;
alert.type = MFAlertTypePopup;
alert.alertStyle = UIAlertControllerStyleAlert;
NSArray <NSDictionary *> *actions = [page array:KeyLinks];
NSMutableArray <UIAlertAction *> *actionsForAlert = [NSMutableArray array];
for (NSDictionary *actionMap in actions) {
[actionsForAlert addObject:[UIAlertAction actionWithTitle:[actionMap stringForKey:KeyTitle] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:delegate];
}]];
}
alert.actions = actionsForAlert;
if ((alert.title.length > 0 || alert.message.length > 0) && alert.actions.count > 0) {
return alert;
} else {
if (error) {
*error = [[MVMCoreErrorObject alloc] initWithTitle:nil messageToLog:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodePopupFailed domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_Popup_pageType:%@",NSStringFromClass([delegate class]),[page stringForKey:KeyPageType]]];
}
return nil;
}
}
@end @end

View File

@ -32,6 +32,8 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
public var inverted = false public var inverted = false
public var size:linkFontSize = linkFontSize.small public var size:linkFontSize = linkFontSize.small
public var shouldMaskRecordedView: Bool? = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializer // MARK: - Initializer
//-------------------------------------------------- //--------------------------------------------------
@ -61,6 +63,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
case activeColor_inverted case activeColor_inverted
case inverted case inverted
case size case size
case shouldMaskRecordedView
} }
public enum linkFontSize: String, Codable { public enum linkFontSize: String, Codable {
@ -117,7 +120,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
if let disabledColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledColor_inverted) { if let disabledColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledColor_inverted) {
self.disabledColor_inverted = disabledColor_inverted self.disabledColor_inverted = disabledColor_inverted
} }
if let activeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor) { if let activeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor) {
self.activeColor = activeColor self.activeColor = activeColor
} }
@ -128,6 +131,8 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
if let size = try typeContainer.decodeIfPresent(linkFontSize.self, forKey: .size) { if let size = try typeContainer.decodeIfPresent(linkFontSize.self, forKey: .size) {
self.size = size self.size = size
} }
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? shouldMaskRecordedView
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
@ -146,5 +151,6 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
try container.encode(activeColor, forKey: .activeColor) try container.encode(activeColor, forKey: .activeColor)
try container.encode(activeColor_inverted, forKey: .activeColor_inverted) try container.encode(activeColor_inverted, forKey: .activeColor_inverted)
try container.encodeIfPresent(size, forKey: .size) try container.encodeIfPresent(size, forKey: .size)
try container.encode(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
} }
} }

View File

@ -42,7 +42,8 @@ import Foundation
public var wasInitiallySelected: Bool = false public var wasInitiallySelected: Bool = false
public var title: String? public var title: String?
public var feedback: String? public var feedback: String?
public var shouldMaskRecordedView: Bool? = true
//used to drive the EntryFieldView UI //used to drive the EntryFieldView UI
public var titleStateLabel: FormLabelModel public var titleStateLabel: FormLabelModel
public var feedbackStateLabel: FormLabelModel public var feedbackStateLabel: FormLabelModel
@ -79,6 +80,7 @@ import Foundation
case fieldKey case fieldKey
case groupName case groupName
case required case required
case shouldMaskRecordedView
} }
//-------------------------------------------------- //--------------------------------------------------
@ -143,6 +145,7 @@ import Foundation
hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) ?? false hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) ?? false
baseValue = text baseValue = text
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? shouldMaskRecordedView
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName self.groupName = groupName
} }
@ -172,5 +175,6 @@ import Foundation
try container.encode(enabled, forKey: .enabled) try container.encode(enabled, forKey: .enabled)
try container.encode(required, forKey: .required) try container.encode(required, forKey: .required)
try container.encode(hideBorders, forKey: .hideBorders) try container.encode(hideBorders, forKey: .hideBorders)
try container.encode(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
} }
} }

View File

@ -337,12 +337,16 @@ import UIKit
text = model.text text = model.text
placeholder = model.placeholder placeholder = model.placeholder
textField.shouldMaskWhileRecording = model.shouldMaskRecordedView ?? true
switch model.type { switch model.type {
case .password, .secure: case .password, .secure:
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
textField.shouldMaskWhileRecording = true
case .numberSecure: case .numberSecure:
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
textField.shouldMaskWhileRecording = true
textField.keyboardType = .numberPad textField.keyboardType = .numberPad
case .number: case .number:

View File

@ -23,6 +23,7 @@ import MVMCore
public var baseValue: AnyHashable? public var baseValue: AnyHashable?
public var enabled: Bool = true public var enabled: Bool = true
public var readOnly: Bool = false public var readOnly: Bool = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Methods // MARK: - Methods
//-------------------------------------------------- //--------------------------------------------------

View File

@ -26,6 +26,7 @@
public var localBundle: Bundle? public var localBundle: Bundle?
public var cornerRadius: CGFloat? public var cornerRadius: CGFloat?
public var clipsImage: Bool? public var clipsImage: Bool?
public var shouldMaskRecordedView: Bool? = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializer // MARK: - Initializer
@ -54,5 +55,6 @@
case contentMode case contentMode
case cornerRadius case cornerRadius
case clipsImage case clipsImage
case shouldMaskRecordedView
} }
} }

View File

@ -12,7 +12,8 @@ import MVMCore
public typealias ActionBlock = () -> () public typealias ActionBlock = () -> ()
@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol { @objcMembers open class Label: UILabel, MVMCoreViewProtocol, MoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol, ViewMaskingProtocol {
//------------------------------------------------------ //------------------------------------------------------
// MARK: - Properties // MARK: - Properties
//------------------------------------------------------ //------------------------------------------------------
@ -41,6 +42,8 @@ public typealias ActionBlock = () -> ()
NSRange(location: 0, length: text?.count ?? 0) NSRange(location: 0, length: text?.count ?? 0)
} }
public var shouldMaskWhileRecording: Bool = false
//------------------------------------------------------ //------------------------------------------------------
// MARK: - Multi-Action Text // MARK: - Multi-Action Text
//------------------------------------------------------ //------------------------------------------------------
@ -244,6 +247,7 @@ public typealias ActionBlock = () -> ()
text = nil text = nil
attributedText = nil attributedText = nil
originalAttributedString = nil originalAttributedString = nil
shouldMaskWhileRecording = model.shouldMaskRecordedView ?? false
guard let labelModel = model as? LabelModel else { return } guard let labelModel = model as? LabelModel else { return }

View File

@ -26,6 +26,7 @@
public var hero: Int? public var hero: Int?
public var makeWholeViewClickable: Bool? public var makeWholeViewClickable: Bool?
public var numberOfLines: Int? public var numberOfLines: Int?
public var shouldMaskRecordedView: Bool? = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Keys // MARK: - Keys
@ -46,6 +47,7 @@
case hero case hero
case makeWholeViewClickable case makeWholeViewClickable
case numberOfLines case numberOfLines
case shouldMaskRecordedView
} }
enum AttributeTypeKey: String, CodingKey { enum AttributeTypeKey: String, CodingKey {
@ -79,6 +81,7 @@
hero = try typeContainer.decodeIfPresent(Int.self, forKey: .hero) hero = try typeContainer.decodeIfPresent(Int.self, forKey: .hero)
makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable) makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable)
numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines) numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines)
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false
} }
open func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
@ -97,5 +100,6 @@
try container.encodeIfPresent(hero, forKey: .hero) try container.encodeIfPresent(hero, forKey: .hero)
try container.encodeIfPresent(makeWholeViewClickable, forKey: .makeWholeViewClickable) try container.encodeIfPresent(makeWholeViewClickable, forKey: .makeWholeViewClickable)
try container.encodeIfPresent(numberOfLines, forKey: .numberOfLines) try container.encodeIfPresent(numberOfLines, forKey: .numberOfLines)
try container.encodeIfPresent(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
} }
} }

View File

@ -22,7 +22,7 @@
public var addSizeConstraintsForAspectRatio = true public var addSizeConstraintsForAspectRatio = true
public var shouldNotifyDelegateOnUpdate = true public var shouldNotifyDelegateOnUpdate = true
public var shouldNotifyDelegateOnDefaultSizeChange = false public var shouldNotifyDelegateOnDefaultSizeChange = false
// Allows for a view to hardcode which height to use if there is none in the json. // Allows for a view to hardcode which height to use if there is none in the json.
var imageWidth: CGFloat? var imageWidth: CGFloat?
var imageHeight: CGFloat? var imageHeight: CGFloat?

View File

@ -41,7 +41,7 @@ public class HeadersH2TinyButtonModel: HeaderModel, MoleculeModelProtocol {
} }
super.setDefaults() super.setDefaults()
button.style = .secondary button.style = .secondary
button.size = .tiny button.size = .small
} }
//-------------------------------------------------- //--------------------------------------------------

View File

@ -51,9 +51,7 @@ open class HeaderView: Container {
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
guard let headerModel = headerModel else { return } guard let headerModel = headerModel else { return }
if let lineModel = headerModel.line { line.setOptional(with: headerModel.line, delegateObject, additionalData)
line.set(with: lineModel, delegateObject, additionalData)
}
} }
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {

View File

@ -30,9 +30,6 @@
if bottomPadding == nil { if bottomPadding == nil {
bottomPadding = PaddingDefaultVerticalSpacing bottomPadding = PaddingDefaultVerticalSpacing
} }
if line == nil {
line = LineModel(type: .heavy)
}
} }
public override init() { public override init() {

View File

@ -0,0 +1,17 @@
//
// MaskedMoleculeProtocol.swift
// MVMCoreUI
//
// Created by Kyle on 6/29/22.
// Copyright © 2022 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol MoleculeMaskingProtocol {
var shouldMaskRecordedView: Bool? { get }
}
public extension MoleculeMaskingProtocol {
var shouldMaskRecordedView: Bool? { return false }
}

View File

@ -5,7 +5,7 @@ public enum MolecularError: Swift.Error {
} }
public protocol MoleculeModelProtocol: ModelProtocol, AccessibilityModelProtocol, MoleculeTreeTraversalProtocol { public protocol MoleculeModelProtocol: ModelProtocol, AccessibilityModelProtocol, MoleculeTreeTraversalProtocol, MoleculeMaskingProtocol {
var moleculeName: String { get } var moleculeName: String { get }
var backgroundColor: Color? { get set } var backgroundColor: Color? { get set }
} }

View File

@ -13,4 +13,5 @@ public protocol PageModelProtocol {
var screenHeading: String? { get set } var screenHeading: String? { get set }
var backgroundColor: Color? { get set } var backgroundColor: Color? { get set }
var navigationBar: (NavigationItemModelProtocol & MoleculeModelProtocol)? { get set } var navigationBar: (NavigationItemModelProtocol & MoleculeModelProtocol)? { get set }
var shouldMaskScreenWhileRecording: Bool? { get }
} }

View File

@ -41,6 +41,9 @@ public extension TemplateProtocol {
var behaviorHandler = self as? PageBehaviorHandlerProtocol else { return } var behaviorHandler = self as? PageBehaviorHandlerProtocol else { return }
behaviorHandlerModel.traverseAndAddRequiredBehaviors() behaviorHandlerModel.traverseAndAddRequiredBehaviors()
behaviorHandler.createBehaviors(for: behaviorHandlerModel, delegateObject: delegateObject) behaviorHandler.createBehaviors(for: behaviorHandlerModel, delegateObject: delegateObject)
if let viewController = self as? UIViewController {
MVMCoreUISession.sharedGlobal()?.applyGlobalBehaviors(to: viewController)
}
} }
func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel { func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel {

View File

@ -0,0 +1,15 @@
//
// ViewMaskingProtocol.swift
// MVMCoreUI
//
// Created by Kyle on 3/7/22.
// Copyright © 2022 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol ViewMaskingProtocol: UIView {
var shouldMaskWhileRecording: Bool { get }
}

View File

@ -30,6 +30,8 @@ import Foundation
public var tabBarHidden: Bool = false public var tabBarHidden: Bool = false
public var tabBarIndex: Int? public var tabBarIndex: Int?
public var shouldMaskScreenWhileRecording: Bool?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializer // MARK: - Initializer
@ -53,6 +55,7 @@ import Foundation
case navigationBar case navigationBar
case tabBarHidden case tabBarHidden
case tabBarIndex case tabBarIndex
case shouldMaskScreenWhileRecording
} }
//-------------------------------------------------- //--------------------------------------------------
@ -77,6 +80,7 @@ import Foundation
self.tabBarHidden = tabBarHidden self.tabBarHidden = tabBarHidden
} }
tabBarIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .tabBarIndex) tabBarIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .tabBarIndex)
shouldMaskScreenWhileRecording = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskScreenWhileRecording)
} }
open func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
@ -89,5 +93,6 @@ import Foundation
try container.encodeModelIfPresent(navigationBar, forKey: .navigationBar) try container.encodeModelIfPresent(navigationBar, forKey: .navigationBar)
try container.encode(tabBarHidden, forKey: .tabBarHidden) try container.encode(tabBarHidden, forKey: .tabBarHidden)
try container.encodeIfPresent(tabBarIndex, forKey: .tabBarIndex) try container.encodeIfPresent(tabBarIndex, forKey: .tabBarIndex)
try container.encode(shouldMaskScreenWhileRecording, forKey: .shouldMaskScreenWhileRecording)
} }
} }

View File

@ -46,7 +46,7 @@
open override func viewForTop() -> UIView? { open override func viewForTop() -> UIView? {
guard let headerModel = templateModel?.header, guard let headerModel = templateModel?.header,
let molecule = ModelRegistry.createMolecule(headerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: headerModel)
else { return super.viewForTop() } else { return super.viewForTop() }
// Temporary, Default the horizontal padding // Temporary, Default the horizontal padding
@ -59,7 +59,7 @@
override open func viewForBottom() -> UIView? { override open func viewForBottom() -> UIView? {
guard let footerModel = templateModel?.footer, guard let footerModel = templateModel?.footer,
let molecule = ModelRegistry.createMolecule(footerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: footerModel)
else { return super.viewForBottom() } else { return super.viewForBottom() }
return molecule return molecule
@ -124,7 +124,9 @@
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath) let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath)
(cell as? MoleculeViewProtocol)?.reset() (cell as? MoleculeViewProtocol)?.reset()
(cell as? MoleculeViewProtocol)?.set(with: moleculeInfo.molecule, delegateObjectIVar, nil) if let molecularCell = cell as? MoleculeViewProtocol {
updateMoleculeView(molecularCell, from: moleculeInfo.molecule)
}
update(cell: cell, size: view.frame.width) update(cell: cell, size: view.frame.width)
// Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells // Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells
cell.layoutIfNeeded() cell.layoutIfNeeded()

View File

@ -58,7 +58,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
open override func viewForTop() -> UIView { open override func viewForTop() -> UIView {
guard let headerModel = templateModel?.header, guard let headerModel = templateModel?.header,
let molecule = ModelRegistry.createMolecule(headerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: headerModel)
else { return super.viewForTop() } else { return super.viewForTop() }
// Temporary, Default the horizontal padding // Temporary, Default the horizontal padding
@ -71,7 +71,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
override open func viewForBottom() -> UIView { override open func viewForBottom() -> UIView {
guard let footerModel = templateModel?.footer, guard let footerModel = templateModel?.footer,
let molecule = ModelRegistry.createMolecule(footerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: footerModel)
else { return super.viewForBottom() } else { return super.viewForBottom() }
return molecule return molecule
@ -140,7 +140,9 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
(cell as? MoleculeViewProtocol)?.reset() (cell as? MoleculeViewProtocol)?.reset()
(cell as? MoleculeListCellProtocol)?.setLines(with: templateModel?.line, delegateObject: delegateObjectIVar, additionalData: nil, indexPath: indexPath) (cell as? MoleculeListCellProtocol)?.setLines(with: templateModel?.line, delegateObject: delegateObjectIVar, additionalData: nil, indexPath: indexPath)
(cell as? MoleculeViewProtocol)?.set(with: moleculeInfo.molecule, delegateObjectIVar, nil) if let moleculeView = cell as? MoleculeViewProtocol {
updateMoleculeView(moleculeView, from: moleculeInfo.molecule)
}
(cell as? MVMCoreViewProtocol)?.updateView(tableView.bounds.width) (cell as? MVMCoreViewProtocol)?.updateView(tableView.bounds.width)
// Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells // Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells
cell.layoutIfNeeded() cell.layoutIfNeeded()

View File

@ -54,7 +54,7 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
open override func viewForTop() -> UIView? { open override func viewForTop() -> UIView? {
guard let headerModel = templateModel?.header, guard let headerModel = templateModel?.header,
let molecule = ModelRegistry.createMolecule(headerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: headerModel)
else { return nil } else { return nil }
return molecule return molecule
@ -73,13 +73,13 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
stackItem.useHorizontalMargins = true stackItem.useHorizontalMargins = true
} }
stack.set(with: moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil) updateMoleculeView(stack, from: moleculeStackModel)
return stack return stack
} }
override open func viewForBottom() -> UIView? { override open func viewForBottom() -> UIView? {
guard let footerModel = templateModel?.footer, guard let footerModel = templateModel?.footer,
let molecule = ModelRegistry.createMolecule(footerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: footerModel)
else { return nil } else { return nil }
return molecule return molecule

View File

@ -27,7 +27,7 @@ import UIKit
open override func viewForTop() -> UIView? { open override func viewForTop() -> UIView? {
guard let headerModel = templateModel?.header, guard let headerModel = templateModel?.header,
let molecule = ModelRegistry.createMolecule(headerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: headerModel)
else { return nil } else { return nil }
return molecule return molecule
@ -35,7 +35,7 @@ import UIKit
open override func viewForMiddle() -> UIView? { open override func viewForMiddle() -> UIView? {
guard let middleModel = templateModel?.middle, guard let middleModel = templateModel?.middle,
let molecule = ModelRegistry.createMolecule(middleModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: middleModel)
else { return nil } else { return nil }
return molecule return molecule
@ -43,7 +43,7 @@ import UIKit
override open func viewForBottom() -> UIView? { override open func viewForBottom() -> UIView? {
guard let footerModel = templateModel?.footer, guard let footerModel = templateModel?.footer,
let molecule = ModelRegistry.createMolecule(footerModel, delegateObject: delegateObjectIVar) let molecule = generateMoleculeView(from: footerModel)
else { return nil } else { return nil }
return molecule return molecule

View File

@ -13,7 +13,8 @@ public protocol TextInputDidDeleteProtocol: AnyObject {
} }
@objcMembers open class TextField: UITextField { @objcMembers open class TextField: UITextField, ViewMaskingProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
@ -23,6 +24,8 @@ public protocol TextInputDidDeleteProtocol: AnyObject {
/// Set to true to hide the blinking textField cursor. /// Set to true to hide the blinking textField cursor.
public var hideBlinkingCaret = false public var hideBlinkingCaret = false
public var shouldMaskWhileRecording: Bool = true
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Delegate // MARK: - Delegate
//-------------------------------------------------- //--------------------------------------------------
@ -97,6 +100,8 @@ extension TextField: MoleculeViewProtocol {
if let accessibilityIdentifier = model.accessibilityIdentifier { if let accessibilityIdentifier = model.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier self.accessibilityIdentifier = accessibilityIdentifier
} }
shouldMaskWhileRecording = model.shouldMaskRecordedView ?? true
} }
open func reset() { open func reset() {

View File

@ -9,7 +9,8 @@
import UIKit import UIKit
@objcMembers open class View: UIView, MoleculeViewProtocol { @objcMembers open class View: UIView, MoleculeViewProtocol, ViewMaskingProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
@ -18,6 +19,10 @@ import UIKit
private var initialSetupPerformed = false private var initialSetupPerformed = false
public var shouldMaskWhileRecording: Bool {
return model?.shouldMaskRecordedView ?? false
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initialization // MARK: - Initialization
//-------------------------------------------------- //--------------------------------------------------

View File

@ -246,6 +246,27 @@ import MVMCore
manager?.newDataReceived?(in: self) manager?.newDataReceived?(in: self)
} }
public func generateMoleculeView(from model: MoleculeModelProtocol) -> MoleculeViewProtocol? {
executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in
behavior.willSetupMolecule(with: model, updating: nil)
}
guard let moleculeView = ModelRegistry.createMolecule(model, delegateObject: delegateObjectIVar) else { return nil }
executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in
behavior.didSetupMolecule(view: moleculeView, withModel: model)
}
return moleculeView
}
public func updateMoleculeView(_ view: MoleculeViewProtocol, from model: MoleculeModelProtocol) {
executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in
behavior.willSetupMolecule(with: model, updating: view)
}
view.set(with: model, delegateObjectIVar, nil)
executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in
behavior.didSetupMolecule(view: view, withModel: model)
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Navigation Item // MARK: - Navigation Item
//-------------------------------------------------- //--------------------------------------------------
@ -322,6 +343,14 @@ import MVMCore
} }
} }
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
executeBehaviors { [weak self] (behavior: PageVisibilityBehavior) in
behavior.willShowPage(self?.delegateObjectIVar)
}
}
open override func viewDidAppear(_ animated: Bool) { open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
@ -330,6 +359,14 @@ import MVMCore
} }
} }
open override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
executeBehaviors { [weak self] (behavior: PageVisibilityBehavior) in
behavior.willHidePage(self?.delegateObjectIVar)
}
}
open override func viewDidDisappear(_ animated: Bool) { open override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated) super.viewDidDisappear(animated)

View File

@ -14,12 +14,17 @@ public protocol PageBehaviorHandlerProtocol {
public extension PageBehaviorHandlerProtocol { public extension PageBehaviorHandlerProtocol {
/// Creates the behaviors and sets the variable. /// Creates the behaviors and sets the variable.
mutating func createBehaviors(for model: PageBehaviorHandlerModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { mutating func createBehaviors(for model: PageBehaviorHandlerModelProtocol, delegateObject: MVMCoreUIDelegateObject?) {
guard let behaviorModels = model.behaviors else {
behaviors = behaviors?.filter { $0.transcendsPageUpdates }
if behaviors?.isEmpty ?? false {
behaviors = nil behaviors = nil
}
guard let behaviorModels = model.behaviors else {
return return
} }
var behaviors: [PageBehaviorProtocol] = [] var behaviors: [PageBehaviorProtocol] = behaviors ?? []
for behaviorModel in behaviorModels { for behaviorModel in behaviorModels {
do { do {

View File

@ -9,25 +9,50 @@
public protocol PageBehaviorProtocol: ModelHandlerProtocol { public protocol PageBehaviorProtocol: ModelHandlerProtocol {
/// Should the behavior persist regardless of page behavior model updates.
var transcendsPageUpdates: Bool { get }
/// Initializes the behavior with the model /// Initializes the behavior with the model
init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?)
} }
public extension PageBehaviorProtocol {
var transcendsPageUpdates: Bool { return false }
}
/** /**
Behavior conforming protocols. Behaviors will conform to one or more of these protocols to receive page lifecycle events that pertain to them. Behavior conforming protocols. Behaviors will conform to one or more of these protocols to receive page lifecycle events that pertain to them.
*/ */
public protocol PageMoleculeTransformationBehavior: PageBehaviorProtocol { public protocol PageMoleculeTransformationBehavior: PageBehaviorProtocol {
func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?)
func willSetupMolecule(with model: MoleculeModelProtocol, updating view: MoleculeViewProtocol?)
func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol)
}
public extension PageMoleculeTransformationBehavior {
// All optional.
func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) {}
func willSetupMolecule(with model: MoleculeModelProtocol, updating view: MoleculeViewProtocol?) {}
func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol) {}
} }
public protocol PageVisibilityBehavior: PageBehaviorProtocol { public protocol PageVisibilityBehavior: PageBehaviorProtocol {
func willShowPage(_ delegateObject: MVMCoreUIDelegateObject?)
func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?)
func willHidePage(_ delegateObject: MVMCoreUIDelegateObject?)
func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?)
} }
public extension PageVisibilityBehavior {
// All optional.
func willShowPage(_ delegateObject: MVMCoreUIDelegateObject?) {}
func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) {}
func willHidePage(_ delegateObject: MVMCoreUIDelegateObject?) {}
func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) {}
}
public protocol PageScrolledBehavior: PageBehaviorProtocol { public protocol PageScrolledBehavior: PageBehaviorProtocol {
func pageScrolled(scrollView: UIScrollView, _ delegateObject: MVMCoreUIDelegateObject?) func pageScrolled(scrollView: UIScrollView, _ delegateObject: MVMCoreUIDelegateObject?)

View File

@ -13,6 +13,7 @@
@class MFViewController; @class MFViewController;
@class MFLoadingViewController; @class MFLoadingViewController;
@class NavigationController; @class NavigationController;
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface MVMCoreUISession : MVMCoreSessionObject @interface MVMCoreUISession : MVMCoreSessionObject
@ -25,18 +26,21 @@ NS_ASSUME_NONNULL_BEGIN
/// Tracks the current page type the user is currently viewing. KVO compliant. /// Tracks the current page type the user is currently viewing. KVO compliant.
@property (nonatomic, strong, nullable) NSString *currentPageType; @property (nonatomic, strong, nullable) NSString *currentPageType;
// for handscroll Animation on subclasses of MFScrollingViewController /// for handscroll Animation on subclasses of MFScrollingViewController
@property (assign, nonatomic) BOOL enableHandScrollAnimation; @property (assign, nonatomic) BOOL enableHandScrollAnimation;
//indicates if the app launched successfully /// indicates if the app launched successfully
@property (assign, nonatomic) BOOL launchAppLoadedSuccessfully; @property (assign, nonatomic) BOOL launchAppLoadedSuccessfully;
// Allows a global overload of the title view of navigation item. /// Allows a global overload of the title view of navigation item.
- (nullable UIView *)titleViewForController:(nonnull MFViewController *)controller; - (nullable UIView *)titleViewForController:(nonnull MFViewController *)controller;
// Sets up the session as delegate for standard load view controller. Pass the view controller that will be used to present and will be disabled when load view is presented. /// Sets up the session as delegate for standard load view controller. Pass the view controller that will be used to present and will be disabled when load view is presented.
- (void)setupAsStandardLoadViewDelegate:(nonnull UIViewController *)mainViewController; - (void)setupAsStandardLoadViewDelegate:(nonnull UIViewController *)mainViewController;
/// Applies additional behaviors to a controller according to the session. Allows for packages to add additional cross cutting concerns.
- (void)applyGlobalBehaviorsToController:(nonnull UIViewController *)viewController;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -62,4 +62,8 @@
self.mainViewController.view.userInteractionEnabled = YES; self.mainViewController.view.userInteractionEnabled = YES;
} }
- (void)applyGlobalBehaviorsToController:(nonnull UIViewController *)viewController {
// Allow extending frameworks to apply behaviors to add cross cutting concerns to the base controllers.
}
@end @end