mvm_core_ui/MVMCoreUI/BaseControllers/MFViewController.m
Pfeil, Scott Robert 98a5e33caf Moved required module checking to the view controller where it belongs.
Broke down the update with response into two separate functions.
Only update loadObject.pageJSON if pageType is the same check....
2019-06-28 11:26:45 -04:00

874 lines
33 KiB
Objective-C

//
// MFViewController.m
// myverizon
//
// Created by Scott Pfeil on 11/26/13.
// Copyright (c) 2013 Verizon Wireless. All rights reserved.
//
#import "MFViewController.h"
@import MVMCore.MVMCoreAlertHandler;
@import MVMCore.MVMCoreSessionTimeHandler;
@import MVMCore.MVMCoreAlertObject;
@import MVMCore.MVMCoreLoadHandler;
@import MVMCore.MVMCoreNavigationHandler;
@import MVMCore.MVMCoreActionHandler;
@import MVMCore.MVMCoreTopAlertObject;
@import MVMCore.MVMCoreDispatchUtility;
@import MVMCore.MVMCoreActionUtility;
@import MVMCore.NSDictionary_MFConvenience;
@import MVMCore.MVMCoreLoadObject;
@import MVMCore.NSArray_MFConvenience;
@import MVMCore.MVMCoreGetterUtility;
@import MVMCore.MVMCoreConstants;
@import MVMCore.MVMCoreCache;
#import "NSLayoutConstraint+MFConvenience.h"
#import "UIColor+MFConvenience.h"
#import "MVMCoreUICommonViewsUtility.h"
#import "MFStyler.h"
#import "MVMCoreUISplitViewController.h"
#import "MVMCoreUITabBarPageControlViewController.h"
#import "MFFonts.h"
#import <MVMCoreUI/MFSizeObject.h>
#import "MVMCoreUIUtility.h"
#import "MVMCoreUIConstants.h"
#import "MVMCoreUISession.h"
#import "MVMCoreUILoggingHandler.h"
#import "MVMCoreUITabBarPageControlViewController.h"
#import "MVMCoreUINavigationController.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
@import MVMAnimationFramework;
@interface MFViewController() <FormValidationProtocol>
// A flag for if this view controller is observing for cache updates or not.
@property (nonatomic) BOOL observingForResponseJSONUpdates;
// A flag for if the initial load is finished or not.
@property (nonatomic) BOOL initialLoadFinished;
// A mapping for mapping text fields for error keys
@property (strong, nonatomic) NSMutableDictionary *textFieldErrorMapping;
// title view for navigation bar, used for custom navigation titles
@property (weak, nonatomic) UILabel *titleLabel;
@property (strong, nonatomic) FormValidator *formValidator;
@end
@implementation MFViewController
- (FormValidator *)formValidatorModel {
if (self.formValidator == nil) {
self.formValidator = [FormValidator new];
}
return self.formValidator;
}
- (void)dismiss {
if (self.presentingViewController) {
[[MVMCoreNavigationHandler sharedNavigationHandler] dismissViewController:self animated:YES];
} else if (self.navigationController) {
[[MVMCoreNavigationHandler sharedNavigationHandler] popViewController:self animated:YES];
}
}
- (BOOL)isVisibleViewController {
return ((self.presentingViewController && !self.presentedViewController) || [self.navigationController topViewController] == self);
}
- (void)registerTextField:(nonnull MFTextField *)textField forErrorKey:(nonnull NSString *)errorKey {
if (!self.textFieldErrorMapping) {
self.textFieldErrorMapping = [NSMutableDictionary dictionary];
}
[self.textFieldErrorMapping setObject:textField forKey:errorKey];
}
- (BOOL)screenSizeChanged {
return !CGSizeEqualToSize(self.previousScreenSize, CGSizeZero) && !fequalwiththreshold(self.previousScreenSize.width, self.view.bounds.size.width, .1);
}
#pragma mark - Functions To Subclass
- (BOOL)shouldFinishProcessingLoad:(nonnull MVMCoreLoadObject *)loadObject error:(MVMCoreErrorObject *_Nonnull *_Nonnull)error {
self.pageType = loadObject.pageType;
self.loadObject = loadObject;
// Verifies all modules needed are loaded.
return [MFViewController verifyRequiredModulesLoadedForLoadObject:loadObject error:error];
}
// Sets the screen to use the screen heading.
// it is required in device flow, where we are showing greeting name as screen heading,
// device details screen heading needs to be updated/refreshed again, if user has changed device nick name
- (NSString *)screenHeading {
NSString *screenHeading = [self.loadObject.pageJSON string:KeyScreenHeading];
return screenHeading;
}
- (void)setScreenHeadingMessage:(nullable NSString *)screenHeadingMessage {
if (screenHeadingMessage.length > 0) {
if (self.titleLabel) {
self.titleLabel.text = screenHeadingMessage;
} else {
self.navigationItem.title = screenHeadingMessage;
}
self.navigationItem.title = screenHeadingMessage;
self.navigationItem.accessibilityLabel = screenHeadingMessage;
if (self.navigationItem.titleView) {
self.navigationItem.titleView.accessibilityLabel = screenHeadingMessage;
}
}
}
- (void)newDataBuildScreen {
UIView *titleView = [[MVMCoreUISession sharedGlobal] titleViewForController:self];
if (titleView) {
self.navigationItem.titleView = titleView;
} else {
// Sets the screen to use the screen heading.
NSString *screenHeading = [self screenHeading];
if (screenHeading) {
[self setScreenHeadingMessage:screenHeading];
}
}
}
- (void)initialLoad {
// Creates an initial load object if needed.
if (!self.loadObject) {
self.loadObject = [[MVMCoreLoadObject alloc] initWithDelegateObject:[self delegateObject]];
}
// Avoid the setter so we are only setting the bool and wait for view will appear to update the navigation bar.
_masterShouldBeAccessible = [self isMasterInitiallyAccessible];
_supportShouldBeAccessible = [self isSupportInitiallyAccessible];
// Observe for cache updates if desired.
[self observeForResponseJSONUpdates];
}
- (void)updateViews {
}
- (void)backButtonPressed {
// Sends keep alive to the server.
[[MVMCoreSessionTimeHandler sharedSessionHandler] sendKeepAliveToServer:NO];
[[MVMCoreNavigationHandler sharedNavigationHandler] popViewController:(self.manager ?: self) animated:YES];
}
- (void)handleErrorAsPopup:(nonnull MVMCoreErrorObject *)error {
// Logs the error.
if (error.logError) {
[MVMCoreLoggingHandler addErrorToLog:error];
}
MVMCoreLog(@"Error: %@ %@ %@ %@",[error stringErrorCode], error.domain, error.location,error.messageToDisplay);
if (!error.silentError) {
// Show alert
MVMCoreAlertObject *alertObject = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO];
[[MVMCoreAlertHandler sharedAlertHandler] showAlertWithAlertObject:alertObject];
}
}
- (BOOL)shouldCacheInManager {
return YES;
}
- (nullable DelegateObject *)delegateObject {
return [MVMCoreUIDelegateObject createWithDelegateForAll:self];
}
#pragma mark - Response Handling
- (void)observeForResponseJSONUpdates {
if (!self.observingForResponseJSONUpdates && (self.pageTypesToListenFor.count > 0 || self.modulesToListenFor.count > 0)) {
self.observingForResponseJSONUpdates = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(responseJSONUpdated:) name:NotificationResponseLoaded object:nil];
}
}
- (void)stopObservingForResponseJSONUpdates {
if (self.observingForResponseJSONUpdates) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NotificationResponseLoaded object:nil];
self.observingForResponseJSONUpdates = NO;
}
}
- (nullable NSArray *)pageTypesToListenFor {
return nil;
}
- (nullable NSArray *)modulesToListenFor {
return nil;
}
- (void)responseJSONUpdated:(nonnull NSNotification *)notification {
// Checks for a page we are listening for.
NSArray *pageTypesListeningFor = [self pageTypesToListenFor];
NSDictionary *pages = [notification.userInfo dict:KeyPageMap];
__block BOOL newData = NO;
[pageTypesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull pageToListenFor, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *page = [pages dict:pageToListenFor];
NSString *pageType = [pages string:KeyPageType];
if (page && [pageType isEqualToString:self.pageType]) {
newData = [self newPageLoaded:page];
*stop = YES;
}
}];
// Checks for modules we are listening for.
NSArray *modulesListeningFor = [self modulesToListenFor];
NSDictionary *modulesReceived = [notification.userInfo dict:KeyModuleMap];
__block NSMutableDictionary *modulesUpdated = [NSMutableDictionary dictionary];
[modulesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull moduleToListenFor, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *module = [modulesReceived dict:moduleToListenFor];
if (module) {
[modulesUpdated setObject:module forKey:moduleToListenFor];
}
}];
if (modulesUpdated.count > 0) {
newData = [self newModulesLoaded:modulesUpdated];
}
if (newData) {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[self newDataBuildAndUpdate];
}];
}
}
- (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 {
// Check if all needed modules are loaded.
__block NSMutableArray *modulesRequired = [NSMutableArray arrayWithArray:[[MVMCoreViewControllerMappingObject sharedViewControllerMappingObject] modulesRequiredForPageType:loadObject.pageType]];
if (modulesRequired.count > 0) {
[[loadObject.modulesJSON allKeys] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (modulesRequired.count == 0) {
*stop = YES;
} else {
NSUInteger index = [modulesRequired indexOfObject:obj];
if (index != NSNotFound) {
[modulesRequired removeObjectAtIndex:index];
}
}
}];
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;
}
}
#pragma mark - Navigation Item, Menu, Support
- (nonnull UIColor *)navigationBarColor {
return [UIColor whiteColor];
}
- (BOOL)navigationBarHidden {
return NO;
}
- (BOOL)navigationBarTransparent {
return NO;
}
- (void)updateNavigationBarUI:(nonnull UINavigationController *)navigationController {
if (navigationController) {
[navigationController setNavigationBarHidden:[self navigationBarHidden] animated:YES];
[UIColor mfSetBackgroundColorForNavigationBar:[self navigationBarColor] navigationBar:navigationController.navigationBar transparent:[self navigationBarTransparent]];
UIColor *navigationBarTintColor = [self navigationBarTintColor] ?: [UIColor blackColor];
navigationController.navigationBar.tintColor = navigationBarTintColor;
// Have the navigation title match the tint color
if (self.titleLabel) {
self.titleLabel.textColor = navigationBarTintColor;
} else {
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithDictionary:navigationController.navigationBar.titleTextAttributes];
[attributes setObject:navigationBarTintColor forKey:NSForegroundColorAttributeName];
navigationController.navigationBar.titleTextAttributes = attributes;
}
if (navigationController == [MVMCoreUISplitViewController mainSplitViewController].navigationController) {
// Update icons if main navigation controller.
[[MVMCoreUISession sharedGlobal].splitViewController setupPanels];
[self setMasterShouldBeAccessible:self.masterShouldBeAccessible];
[self setSupportShouldBeAccessible:self.supportShouldBeAccessible];
[self showBottomProgressBar];
[[MVMCoreUISession sharedGlobal].splitViewController setNavigationIconColor:navigationBarTintColor];
// Update separator.
UIView *separatorView = (UIView *)[MVMCoreUISession sharedGlobal].navigationController.separatorView;
separatorView.hidden = ([self isKindOfClass:[MVMCoreUITabBarPageControlViewController class]]
|| self.manager
|| self.loadObject.requestParameters.tabWasPressed);
}
} else {
[[MVMCoreUISession sharedGlobal].splitViewController.parentViewController setNeedsStatusBarAppearanceUpdate];
}
}
- (BOOL)isMasterInitiallyAccessible {
if ([self.loadObject.pageJSON boolForKey:KeyHideMainMenu]) {
return NO;
}
return [MVMCoreUISession sharedGlobal].launchAppLoadedSuccessfully;
}
- (void)setMasterShouldBeAccessible:(BOOL)masterShouldBeAccessible {
MVMCoreUISplitViewController *splitViewController = [MVMCoreUISession sharedGlobal].splitViewController;
if (self.manager && [self.manager respondsToSelector:@selector(setMasterShouldBeAccessible:)]) {
[(MFViewController *)self.manager setMasterShouldBeAccessible:masterShouldBeAccessible];
} else if ([self isVisibleViewController]) {
[splitViewController setLeftPanelIsAccessible:masterShouldBeAccessible forViewController:self];
}
_masterShouldBeAccessible = masterShouldBeAccessible;
}
- (BOOL)isSupportInitiallyAccessible {
return [MVMCoreUISession sharedGlobal].launchAppLoadedSuccessfully || [self showRightPanelForScreenBeforeLaunchApp];
}
- (BOOL)showRightPanelForScreenBeforeLaunchApp {
return [self.loadObject.pageJSON lenientBoolForKey:@"showRightPanel"];
}
- (BOOL)isOverridingRightButton {
NSDictionary *rightPanelLinkDict = [self.loadObject.pageJSON dict:@"rightPanelButtonLink"];
if (rightPanelLinkDict) {
[[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:rightPanelLinkDict additionalData:nil delegateObject:[self delegateObject]];
return YES;
} else {
return NO;
}
}
- (BOOL)isOverridingLeftButton {
NSDictionary *leftPanelLinkDict = [self.loadObject.pageJSON dict:@"leftPanelButtonLink"];
if (leftPanelLinkDict) {
[[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:leftPanelLinkDict additionalData:nil delegateObject:[self delegateObject]];
return YES;
} else {
return NO;
}
}
- (void)setSupportShouldBeAccessible:(BOOL)supportShouldBeAccessible {
MVMCoreUISplitViewController *splitViewController = [MVMCoreUISession sharedGlobal].splitViewController;
if (self.manager && [self.manager respondsToSelector:@selector(setSupportShouldBeAccessible:)]) {
[(MFViewController *)self.manager setSupportShouldBeAccessible:supportShouldBeAccessible];
} else if ([self isVisibleViewController]) {
[splitViewController setRightPanelIsAccessible:supportShouldBeAccessible forViewController:self];
}
_supportShouldBeAccessible = supportShouldBeAccessible;
}
- (BOOL)mainTableView:(MainMenuViewController *)mainTableView shouldSelectOptionAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
// sub class to change the navigation bar color
- (UIColor *)navigationBarTintColor {
return nil;
}
- (void)showBottomProgressBar {
MVMCoreUISplitViewController *splitViewController = [MVMCoreUISession sharedGlobal].splitViewController;
if ([self isVisibleViewController]) {
NSString *progressAsString = [self.loadObject.pageJSON stringForKey:KeyProgressPercent];
float progress = progressAsString.length > 0 ? [progressAsString floatValue]/100 : 0;
[splitViewController setBottomProgressBarProgress:progress];
}
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
if ([MVMCoreUISplitViewController mainSplitViewController]) {
self.navigationItem.hidesBackButton = YES;
}
// init intro animation manager
MVMAnimationManager *introAnimationManager = [[MVMAnimationManager alloc] init];
self.introAnimationManager = introAnimationManager;
// Present the tooltip from the bottom over the tab bar controller.
if ([MVMCoreGetterUtility isOnIPad]) {
// Different style for ipad.
self.modalPresentationStyle = UIModalPresentationFormSheet;
} else {
// Standard.
self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
}
MVMCoreLog(@"View Controller Loaded : %@",NSStringFromClass([self class]));
// Do some initial loading.
if (!self.initialLoadFinished) {
self.initialLoadFinished = YES;
[self initialLoad];
}
// Since we have new data, build stuff for the screen and update the ui once the screen is done laying out.
[self newDataBuildAndUpdate];
self.needToupdateUIOnScreenSizeChanges = YES;
if (UIAccessibilityIsVoiceOverRunning()) {
self.disableAnimations = YES;
}
if (!self.disableAnimations) {
[self setupIntroAnimations];
}
}
- (void)newDataBuildAndUpdate {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[self newDataBuildScreen];
[self.formValidator enableByValidation];
self.needToUpdateUI = YES;
[self.view setNeedsLayout];
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
[[MVMCoreCache sharedCache] clearImageCache];
}
- (void)viewDidLayoutSubviews {
// Updates the views if necessary
if (self.needToUpdateUI || (self.needToupdateUIOnScreenSizeChanges && [self screenSizeChanged])) {
// Add to fix a strange bug where the width is zero and things get messed up.
if ([self isViewLoaded] && (NSInteger)CGRectGetWidth(self.view.bounds) > 1) {
[self updateViews];
self.needToUpdateUI = NO;
}
}
self.previousScreenSize = self.view.bounds.size;
[super viewDidLayoutSubviews];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Update the navigation bar ui when view is appearing. Don't handle if there is a tab bar page control, it will be handled later.
if (!self.manager) {
[self updateNavigationBarUI:self.navigationController];
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Don't track page state if there is a tab bar page control, it will be handled later.
if (!self.manager) {
[self adobeTrackPageState];
}
// perform intro animations
if (!self.disableAnimations) {
[self.introAnimationManager performAnimations];
}
}
- (void)dealloc {
[self stopObservingForResponseJSONUpdates];
MVMCoreLog(@"%@ deallocated", [[self class] description]);
}
- (BOOL)shouldAutorotate {
return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
if ([MVMCoreGetterUtility isOnIPad]) {
return UIInterfaceOrientationMaskAll;
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
//this method is needed for getting status bar style from present viewcotnroller
- (UIStatusBarStyle)preferredStatusBarStyle {
if ([self respondsToSelector:@selector(defaultStatusBarStyle)]) {
return [self defaultStatusBarStyle];
} else {
return UIStatusBarStyleDefault;
}
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// Updates the detail view width.
void (^completion)(id<UIViewControllerTransitionCoordinatorContext>) = ^(id<UIViewControllerTransitionCoordinatorContext> context) {
[self.view setNeedsLayout];
};
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
} completion:completion];
}
- (BOOL)viewRespectsSystemMinimumLayoutMargins {
return NO;
}
#pragma mark - UITextField Functions
// To Remove TextFields Bug: Keyboard is not dismissing after reaching textfield max length limit
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.selectedField = textField;
//Accessibility
if (UIAccessibilityIsVoiceOverRunning()) {
if ([self textFieldHasDoneButton:textField]) {//If there is no toolbar and done, input view can't be dismissed
[self.view setAccessibilityElements:@[textField.inputView,textField.inputAccessoryView]];
}
[self performSelector:@selector(focusElement:) withObject:textField.inputView afterDelay:0.1];
}
}
- (BOOL)textFieldHasDoneButton:(UITextField *)textField {
return [textField.inputAccessoryView isKindOfClass:[UIToolbar class]] && [[[((UIToolbar *)textField.inputAccessoryView) items] lastObject] isKindOfClass:[UIBarButtonItem class]] && [textField.inputView isKindOfClass:[UIPickerView class]];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (textField == self.selectedField) {
//Accessibility
if (UIAccessibilityIsVoiceOverRunning()) {
[self.view setAccessibilityElements:nil];
[self performSelector:@selector(focusElement:) withObject:textField afterDelay:0.1];
}
self.selectedField = nil;
}
}
- (void)dismissFieldInput:(id)sender {
if (self.selectedField) {
[self.selectedField resignFirstResponder];
}
}
#pragma mark - UITextView Functions
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
self.selectedField = textView;
return YES;
}
- (void)textViewDidEndEditing:(UITextView *)textView {
if (textView == self.selectedField) {
self.selectedField = nil;
}
}
#pragma mark - TableView
- (NSInteger)getNumberOfSections {
NSInteger numberOfSections = 1;
return numberOfSections;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger numberOfSections = 0;
// Fixes a funky issue where the table is being loaded before it should be.
if (CGRectGetWidth(tableView.bounds) > 1) {
numberOfSections = [self getNumberOfSections];
}
return numberOfSections;
}
#pragma mark - ButtonDelegateProtocol
- (BOOL)button:(nonnull NSObject <MFButtonProtocol> *)button shouldPerformActionWithMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData {
return YES;
}
#pragma mark - MVMCoreActionDelegateProtocol
- (void)logActionWithActionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData {
[[MVMCoreUILoggingHandler sharedLoggingHandler] defaultLogActionForController:self actionInformation:actionInformation additionalData:additionalData];
}
- (void)handleOpenPageForRequestParameters:(nonnull MVMCoreRequestParameters *)requestParameters actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData {
if (requestParameters.openSupportPanel) {
[[MVMCoreUISession sharedGlobal].splitViewController.rightPanel willOpenWithActionInformation:actionInformation];
}
[self.formValidator addFormParamsWithRequestParameters:requestParameters];
requestParameters.parentPageType = [self.loadObject.pageJSON stringForKey:@"parentPageType"];
[[MVMCoreLoadHandler sharedGlobal] loadRequest:requestParameters dataForPage:additionalData delegateObject:[self delegateObject]];
}
- (void)handleBackAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData {
BOOL openSupportPanel = [actionInformation boolForKey:KeyOpenSupport];
if (openSupportPanel) {
[[MVMCoreUISession sharedGlobal].splitViewController.rightPanel willOpenWithActionInformation:actionInformation];
}
if ([self.manager respondsToSelector:@selector(handleBackAction:additionalData:)]) {
[((UIViewController <MVMCoreActionDelegateProtocol>*)self.manager) handleBackAction:actionInformation additionalData:additionalData];
} else {
[self dismiss];
}
}
- (void)shouldLinkAwayWithURL:(nullable NSURL *)URL appURL:(nullable NSURL *)appURL actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData linkAwayBlock:(nonnull void (^)(NSURL * _Nullable, NSURL * _Nullable, NSDictionary * _Nullable, NSDictionary * _Nullable))linkAwayBlock {
linkAwayBlock(appURL,URL,actionInformation,additionalData);
}
- (void)prepareRequestForPreviousSubmission:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData submit:(nonnull void (^)(MVMCoreRequestParameters * _Nonnull requestParameters, NSDictionary * _Nullable dataForPage))submit {
// Combines data
NSDictionary *dataForPage = self.loadObject.dataForPage;
if (dataForPage && additionalData) {
NSMutableDictionary *mutableData = [NSMutableDictionary dictionaryWithDictionary:dataForPage];
[mutableData addEntriesFromDictionary:additionalData];
dataForPage = mutableData;
} else if (additionalData) {
dataForPage = additionalData;
}
// Makes previous request
submit(self.loadObject.requestParameters,dataForPage);
}
- (void)willShowPopupWithAlertObject:(nonnull MVMCoreAlertObject *)alertObject alertJson:(nonnull NSDictionary *)alertJson {
}
- (nullable MVMCoreAlertObject *)willShowTopAlertWithAlertObject:(nonnull MVMCoreAlertObject *)alertObject alertJson:(nonnull NSDictionary *)alertJson {
if (self.currentTopAlertPageType && [self.currentTopAlertPageType isEqualToString:[alertJson string:KeyPageType]]) {
return nil;
} else {
return alertObject;
}
}
// Handle cancel
- (void)handleCancel:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData {
}
- (void)handleUnknownActionType:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData {
[MVMCoreActionHandler defaultHandleUnknownActionType:actionType actionInformation:actionInformation additionalData:additionalData delegateObject:[self delegateObject]];
}
- (void)handleActionError:(nonnull MVMCoreErrorObject *)error additionalData:(nullable NSDictionary *)additionalData {
[MVMCoreActionHandler defaultHandleActionError:error additionalData:additionalData];
}
- (void)prepareForOpenOtherAppModule:(nullable NSString *)module {
}
#pragma mark - MVMCoreLoadDelegateProtocol
- (BOOL)checkForDelegateSpecificErrors:(nullable MVMCoreErrorObject *)errorObject loadObject:(nonnull MVMCoreLoadObject *)loadObject completionHandler:(nonnull void (^)(BOOL shouldContinueLoad, MVMCoreLoadObject * _Nullable loadObject, MVMCoreErrorObject * _Nullable error))completionHandler {
return [MVMCoreLoadHandler defaultCheckForSpecificErrors:errorObject loadObject:loadObject];
}
- (BOOL)shouldContinueToErrorPage:(nonnull MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error {
return YES;
}
- (BOOL)handleModuleError:(nonnull NSString *)module loadObject:(nonnull MVMCoreLoadObject *)loadObject error:(nonnull MVMCoreErrorObject *)error {
return [MVMCoreLoadHandler defaultHandleModuleError:module loadObject:loadObject error:error];
}
- (nullable MVMCoreAlertObject *)alertObjectToShow:(nonnull MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)errorObject {
return [MVMCoreAlertObject alertObjectForLoadObject:loadObject error:errorObject delegateObject:[self delegateObject]];
}
- (void)handleFieldErrors:(nullable NSArray *)fieldErrors loadObject:(nonnull MVMCoreLoadObject *)loadObject {
if (self.textFieldErrorMapping.count > 0) {
NSMutableArray *enabledTextField = [NSMutableArray new];
for (NSUInteger i = 0; i < fieldErrors.count; i++) {
NSDictionary *info = [fieldErrors objectAtIndex:i ofType:[NSDictionary class]];
NSString *fieldName = [info stringForKey:KeyFieldName];
MFTextField *textField = [self.textFieldErrorMapping objectForKey:fieldName ofType:[MFTextField class]];
if (textField && textField.enabled) {
[textField setErrorMessage:[info stringForKey:KeyUserMessage]];
[enabledTextField addObject:textField];
}
}
if ([enabledTextField count] > 0) {
MFTextField *firstErrorTextField = enabledTextField[0];
[firstErrorTextField pushAccessibilityNotification];
}
}
}
- (void)loadFinished:(nullable MVMCoreLoadObject *)loadObject loadedViewController:(nullable MFViewController *)loadedViewController error:(nullable MVMCoreErrorObject *)error {
// Open the support panel
#warning Scott/Chris, decide if we want to do this if there is an error.
if (!error && (loadObject.requestParameters.openSupportPanel || [loadObject.systemParametersJSON boolForKey:KeyOpenSupport])) {
[[MVMCoreUISession sharedGlobal].splitViewController showRightPanelAnimated:YES];
}
[MVMCoreUILoggingHandler logWithDelegateLoadFinished:loadObject loadedViewController:loadedViewController error:error];
}
- (void)loadCancelled:(nullable MVMCoreLoadObject *)loadObject {
}
#pragma mark - TopAlertDelegateProtocol
- (void)topAlertViewShown:(nonnull id)topAlert topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject {
self.currentTopAlertPageType = topAlertObject.pageType;
}
- (void)topAlertViewDismissed:(nonnull id)topAlert {
self.currentTopAlertPageType = nil;
}
- (BOOL)shouldLoadTopAlertAction:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData {
if (![[actionMap stringForKey:KeyPageType] isEqualToString:self.loadObject.requestParameters.pageType]) {
return YES;
} else {
return NO;
}
}
#pragma mark - MVMCoreViewManagerViewControllerProtocol
- (void)viewControllerReadyInManager:(nonnull id <MVMCoreViewManagerProtocol>)manager {
// The screen is officially ready. Only update the navigation bar if initial load has finished.
if (self.initialLoadFinished) {
[self updateNavigationBarUI:self.manager.navigationController];
}
[self adobeTrackPageState];
}
- (void)setManager:(UIViewController <MVMCoreViewManagerProtocol>*)manager {
_manager = manager;
if ([manager isKindOfClass:MVMCoreUITabBarPageControlViewController.class]) {
self.tabBarPageControl = (MVMCoreUITabBarPageControlViewController *)manager;
}
}
#pragma mark - MoleculeDelegateProtocol
- (NSDictionary *)getModuleWithName:(NSString *)name {
if (!name) {
return nil;
}
return [self.loadObject.modulesJSON dict:name];
}
#pragma mark - adobe analytics
- (nullable NSArray <NSDictionary *> *)additionalActionsToTrackWithMainActionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData {
return nil;
}
- (nullable NSDictionary *)getActionTrackDataDictionaryForActionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData {
return [[MVMCoreUILoggingHandler sharedLoggingHandler] defaultGetActionTrackDataDictionaryForController:self actionInformation:actionInformation additionalData:additionalData];
}
- (void)adobeTrackPageState {
[[MVMCoreUILoggingHandler sharedLoggingHandler] defaultLogPageStateForController:self];
}
- (nullable NSDictionary *)additionalDataToTrackActionWithActionInformation:(nullable NSDictionary *)actionInformation {
return nil;
}
- (nullable NSDictionary *)additionalDataToTrackForPage {
return nil;
}
- (nullable NSArray *)dynamicPageNameValuesToTrackPage {
return nil;
}
//Accessibility
- (void) focusElement:(id) element {
dispatch_async(dispatch_get_main_queue(), ^{
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
});
}
#pragma mark - Animations
// subclass to override default intro animations
-(void) setupIntroAnimations {
}
@end