mvm_core_ui/MVMCoreUI/BaseControllers/MFViewController.m
Pfeil, Scott Robert 6fde7bc8b4 two typo fix
list and stack template required molecules
2019-06-28 13:34:15 -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 = [page 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