// // 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 "NSLayoutConstraint+MFConvenience.h" #import "UIColor+MFConvenience.h" #import "MVMCoreUICommonViewsUtility.h" #import "MFStyler.h" #import "MVMCoreUISplitViewController.h" #import "MVMCoreUITabBarPageControlViewController.h" #import "MFLoadImageView.h" #import "MFFonts.h" #import #import "MVMCoreUIUtility.h" #import "MVMCoreUIConstants.h" #import "MVMCoreUISession.h" #import "MVMCoreUILoggingHandler.h" #import "MVMCoreUITabBarPageControlViewController.h" @import MVMAnimationFramework; @interface MFViewController () // 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; @end @implementation MFViewController - (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.loadObject = loadObject; self.pageType = loadObject.pageType; return YES; } // 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] initWithDelegate:self]; } // 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; } #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 NSDictionary *pageUpdated = nil; [pageTypesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull pageToListenFor, NSUInteger idx, BOOL * _Nonnull stop) { NSDictionary *page = [pages dict:pageToListenFor]; if (page) { pageUpdated = page; *stop = YES; } }]; // Checks for modules we are listening for. NSArray *modulesListeningFor = [self modulesToListenFor]; NSDictionary *modules = [notification.userInfo dict:KeyModuleMap]; __block NSMutableDictionary *modulesUpdated = [NSMutableDictionary dictionary]; [modulesListeningFor enumerateObjectsUsingBlock:^(NSString * _Nonnull moduleToListenFor, NSUInteger idx, BOOL * _Nonnull stop) { NSDictionary *module = [modules dict:moduleToListenFor]; if (module) { [modulesUpdated setObject:module forKey:moduleToListenFor]; } }]; [self updateWithResponsePage:pageUpdated modules:modulesUpdated]; } - (void)updateWithResponsePage:(nullable NSDictionary *)page modules:(nullable NSDictionary *)modules { if (page || modules.count > 0) { [MVMCoreDispatchUtility performBlockOnMainThread:^{ if (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; } } if (page) { self.loadObject.pageJSON = page; } [self newDataBuildScreen]; self.needToUpdateUI = YES; [self.view setNeedsLayout]; [self.view layoutIfNeeded]; }]; } } #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:NO]; [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. [self setMasterShouldBeAccessible:self.masterShouldBeAccessible]; [self setSupportShouldBeAccessible:self.supportShouldBeAccessible]; [self showBottomProgressBar]; [[MVMCoreUISession sharedGlobal].splitViewController setNavigationIconColor:navigationBarTintColor]; // Update separator. UIView *separatorView = (UIView *)[MVMCoreUISession sharedGlobal].splitViewController.navigationBarSeparator; separatorView.hidden = ([self isKindOfClass:[MVMCoreUITabBarPageControlViewController class]] || self.manager || self.loadObject.requestParameters.tabWasPressed); } } } - (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"]; } - (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. [self newDataBuildScreen]; // Update the UI after the view is loaded. self.needToUpdateUI = YES; self.needToupdateUIOnScreenSizeChanges = YES; if (UIAccessibilityIsVoiceOverRunning()) { self.disableAnimations = YES; } if (!self.disableAnimations) { [self setupIntroAnimations]; } } - (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; } } - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; // Updates the detail view width. void (^completion)(id) = ^(id context) { [self.view setNeedsLayout]; }; [coordinator animateAlongsideTransition:^(id context) { } completion:completion]; } #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 *)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]; } requestParameters.parentPageType = [self.loadObject.pageJSON stringForKey:@"parentPageType"]; [[MVMCoreLoadHandler sharedGlobal] loadRequest:requestParameters dataForPage:additionalData delegate:self]; } - (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 *)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 delegate:self]; } - (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 actionDelegate:self]; } - (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 )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 *)manager { _manager = manager; if ([manager isKindOfClass:MVMCoreUITabBarPageControlViewController.class]) { self.tabBarPageControl = (MVMCoreUITabBarPageControlViewController *)manager; } } #pragma mark - adobe analytics - (nullable NSArray *)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