diff --git a/tns-core-modules/timer/timer.ios.ts b/tns-core-modules/timer/timer.ios.ts index cf780daa6d..aa88711611 100644 --- a/tns-core-modules/timer/timer.ios.ts +++ b/tns-core-modules/timer/timer.ios.ts @@ -25,7 +25,11 @@ class TimerTargetImpl extends NSObject { public tick(timer): void { if (!this.disposed) { - this.callback(); + try { + this.callback(); + } catch (e) { + // TODO + } } if (!this.shouldRepeat) { diff --git a/tns-core-modules/ui/frame/frame-common.ts b/tns-core-modules/ui/frame/frame-common.ts index a4a3407798..ba3e1ad97f 100644 --- a/tns-core-modules/ui/frame/frame-common.ts +++ b/tns-core-modules/ui/frame/frame-common.ts @@ -45,7 +45,7 @@ export function reloadPage(): void { create: currentEntry.create, moduleName: currentEntry.moduleName, backstackVisible: currentEntry.backstackVisible - } + }; frame.navigate(newEntry); } @@ -72,7 +72,7 @@ const moduleCreatePage = profile("module.createPage", (moduleNamePath: string, m if (traceEnabled()) { traceWrite("Calling createPage()", traceCategories.Navigation); } - var page = moduleExports.createPage(); + const page = moduleExports.createPage(); let cssFileName = resolveFileName(moduleNamePath, "css"); // If there is no cssFile only appCss will be applied at loaded. @@ -204,7 +204,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition { const navigationContext: NavigationContext = { entry: backstackEntry, isBackNavigation: true - } + }; this._navigationQueue.push(navigationContext); @@ -273,7 +273,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition { const navigationContext: NavigationContext = { entry: backstackEntry, isBackNavigation: false - } + }; this._navigationQueue.push(navigationContext); @@ -367,34 +367,38 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition { @profile private performNavigation(navigationContext: NavigationContext) { - let navContext = navigationContext.entry; + if (navigationContext) { + let navContext = navigationContext.entry; + + // TODO: This should happen once navigation is completed. + if (navContext && navContext.entry && navContext.entry.clearHistory) { + // Don't clear backstack immediately or we can't remove pages from frame. + } else if (FrameBase._isEntryBackstackVisible(this._currentEntry)) { + this._backStack.push(this._currentEntry); + } - // TODO: This should happen once navigation is completed. - if (navigationContext.entry.entry.clearHistory) { - // Don't clear backstack immediately or we can't remove pages from frame. - } else if (FrameBase._isEntryBackstackVisible(this._currentEntry)) { - this._backStack.push(this._currentEntry); + this._onNavigatingTo(navContext, navigationContext.isBackNavigation); + this._navigateCore(navContext); } - - this._onNavigatingTo(navContext, navigationContext.isBackNavigation); - this._navigateCore(navContext); } @profile private performGoBack(navigationContext: NavigationContext) { - let backstackEntry = navigationContext.entry; - if (!backstackEntry) { - backstackEntry = this._backStack.pop(); - navigationContext.entry = backstackEntry; - } else { - const index = this._backStack.indexOf(backstackEntry); - const removed = this._backStack.splice(index + 1); - this._backStack.pop(); - this._removeBackstackEntries(removed); + if (navigationContext) { + let backstackEntry = navigationContext.entry; + if (!backstackEntry) { + backstackEntry = this._backStack.pop(); + navigationContext.entry = backstackEntry; + } else { + const index = this._backStack.indexOf(backstackEntry); + const removed = this._backStack.splice(index + 1); + this._backStack.pop(); + this._removeBackstackEntries(removed); + } + + this._onNavigatingTo(backstackEntry, true); + this._goBackCore(backstackEntry); } - - this._onNavigatingTo(backstackEntry, true); - this._goBackCore(backstackEntry); } public _goBackCore(backstackEntry: BackstackEntry) { @@ -414,7 +418,9 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition { this.currentPage.onNavigatingFrom(isBack); } - backstackEntry.resolvedPage.onNavigatingTo(backstackEntry.entry.context, isBack, backstackEntry.entry.bindingContext); + if (backstackEntry && backstackEntry.resolvedPage) { + backstackEntry.resolvedPage.onNavigatingTo(backstackEntry.entry.context, isBack, backstackEntry.entry.bindingContext); + } } public get animated(): boolean { diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts index d039fae758..431f680179 100644 --- a/tns-core-modules/ui/frame/frame.android.ts +++ b/tns-core-modules/ui/frame/frame.android.ts @@ -168,34 +168,39 @@ export class Frame extends FrameBase { } transaction.replace(this.containerViewId, newFragment, newFragmentTag); - transaction.commit(); + transaction.commitAllowingStateLoss(); } public _goBackCore(backstackEntry: BackstackEntry) { super._goBackCore(backstackEntry); - navDepth = backstackEntry.navDepth; - const activity = this._android.activity; - const manager = activity.getFragmentManager(); - const transaction = manager.beginTransaction(); + if (backstackEntry) { + navDepth = backstackEntry.navDepth; - if (!backstackEntry.fragment) { - // Happens on newer API levels. On older all fragments - // are recreated once activity is created. - // This entry fragment was destroyed by app suspend. - // We need to recreate its animations and then reverse it. - backstackEntry.fragment = this.createFragment(backstackEntry, backstackEntry.fragmentTag); - _updateTransitions(backstackEntry); - } + const activity = this._android.activity; + if (activity) { + const manager = activity.getFragmentManager(); + const transaction = manager.beginTransaction(); + + if (!backstackEntry.fragment) { + // Happens on newer API levels. On older all fragments + // are recreated once activity is created. + // This entry fragment was destroyed by app suspend. + // We need to recreate its animations and then reverse it. + backstackEntry.fragment = this.createFragment(backstackEntry, backstackEntry.fragmentTag); + _updateTransitions(backstackEntry); + } - const transitionReversed = _reverseTransitions(backstackEntry, this._currentEntry); - if (!transitionReversed) { - // If transition were not reversed then use animations. - transaction.setCustomAnimations(AnimationType.popEnterFakeResourceId, AnimationType.popExitFakeResourceId, AnimationType.enterFakeResourceId, AnimationType.exitFakeResourceId); - } + const transitionReversed = _reverseTransitions(backstackEntry, this._currentEntry); + if (!transitionReversed) { + // If transition were not reversed then use animations. + transaction.setCustomAnimations(AnimationType.popEnterFakeResourceId, AnimationType.popExitFakeResourceId, AnimationType.enterFakeResourceId, AnimationType.exitFakeResourceId); + } - transaction.replace(this.containerViewId, backstackEntry.fragment, backstackEntry.fragmentTag); - transaction.commit(); + transaction.replace(this.containerViewId, backstackEntry.fragment, backstackEntry.fragmentTag); + transaction.commitAllowingStateLoss(); + } + } } public _removeBackstackEntries(removed: BackstackEntry[]): void { diff --git a/tns-core-modules/ui/frame/frame.ios.ts b/tns-core-modules/ui/frame/frame.ios.ts index a487fb2b67..f20f49296f 100644 --- a/tns-core-modules/ui/frame/frame.ios.ts +++ b/tns-core-modules/ui/frame/frame.ios.ts @@ -30,7 +30,11 @@ class NotificationObserver2 extends NSObject { } public onReceive(notification: NSNotification): void { - this._onReceiveCallback(notification); + if (this._onReceiveCallback) { + this._onReceiveCallback(notification); + } else { + handleNotification(notification); + } } public static ObjCExposedMethods = { @@ -96,122 +100,127 @@ export class Frame extends FrameBase { public _navigateCore(backstackEntry: BackstackEntry) { super._navigateCore(backstackEntry); - let viewController: UIViewController = backstackEntry.resolvedPage.ios; - if (!viewController) { - throw new Error("Required page does not have a viewController created."); - } - - let clearHistory = backstackEntry.entry.clearHistory; - if (clearHistory) { - this._clearBackStack(); - navDepth = -1; - } - navDepth++; + if (backstackEntry) { + let viewController: UIViewController = backstackEntry.resolvedPage.ios; + if (!viewController) { + throw new Error("Required page does not have a viewController created."); + } - let navigationTransition: NavigationTransition; - let animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false; - if (animated) { - navigationTransition = this._getNavigationTransition(backstackEntry.entry); - if (navigationTransition) { - viewController[TRANSITION] = navigationTransition; + let clearHistory = backstackEntry.entry.clearHistory; + if (clearHistory) { + this._clearBackStack(); + navDepth = -1; + } + navDepth++; + + let navigationTransition: NavigationTransition; + let animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false; + if (animated) { + navigationTransition = this._getNavigationTransition(backstackEntry.entry); + if (navigationTransition) { + viewController[TRANSITION] = navigationTransition; + } + } + else { + //https://github.com/NativeScript/NativeScript/issues/1787 + viewController[TRANSITION] = { name: "non-animated" }; } - } - else { - //https://github.com/NativeScript/NativeScript/issues/1787 - viewController[TRANSITION] = { name: "non-animated" }; - } - let nativeTransition = _getNativeTransition(navigationTransition, true); - if (!nativeTransition && navigationTransition) { - this._ios.controller.delegate = this._animatedDelegate; - viewController[DELEGATE] = this._animatedDelegate; - } - else { - viewController[DELEGATE] = null; - this._ios.controller.delegate = null; - } + let nativeTransition = _getNativeTransition(navigationTransition, true); + if (!nativeTransition && navigationTransition) { + this._ios.controller.delegate = this._animatedDelegate; + viewController[DELEGATE] = this._animatedDelegate; + } + else { + viewController[DELEGATE] = null; + this._ios.controller.delegate = null; + } - backstackEntry[NAV_DEPTH] = navDepth; - viewController[ENTRY] = backstackEntry; + backstackEntry[NAV_DEPTH] = navDepth; + viewController[ENTRY] = backstackEntry; - // First navigation. - if (!this._currentEntry) { - // Update action-bar with disabled animations before the initial navigation. - this._updateActionBar(backstackEntry.resolvedPage, true); - this._ios.controller.pushViewControllerAnimated(viewController, animated); - if (traceEnabled()) { - traceWrite(`${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, traceCategories.Navigation); + // First navigation. + if (!this._currentEntry) { + // Update action-bar with disabled animations before the initial navigation. + this._updateActionBar(backstackEntry.resolvedPage, true); + this._ios.controller.pushViewControllerAnimated(viewController, animated); + if (traceEnabled()) { + traceWrite(`${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, traceCategories.Navigation); + } + return; } - return; - } - // We should clear the entire history. - if (clearHistory) { - viewController.navigationItem.hidesBackButton = true; - const newControllers = NSMutableArray.alloc().initWithCapacity(1); - newControllers.addObject(viewController); + // We should clear the entire history. + if (clearHistory) { + viewController.navigationItem.hidesBackButton = true; + const newControllers = NSMutableArray.alloc().initWithCapacity(1); + newControllers.addObject(viewController); - // Mark all previous ViewControllers as cleared - const oldControllers = this._ios.controller.viewControllers; - for (let i = 0; i < oldControllers.count; i++) { - (oldControllers.objectAtIndex(i)).isBackstackCleared = true; - } + // Mark all previous ViewControllers as cleared + const oldControllers = this._ios.controller.viewControllers; + for (let i = 0; i < oldControllers.count; i++) { + (oldControllers.objectAtIndex(i)).isBackstackCleared = true; + } + + this._ios.controller.setViewControllersAnimated(newControllers, animated); + if (traceEnabled()) { + traceWrite(`${this}.setViewControllersAnimated([${viewController}], ${animated}); depth = ${navDepth}`, traceCategories.Navigation); + } + return; - this._ios.controller.setViewControllersAnimated(newControllers, animated); - if (traceEnabled()) { - traceWrite(`${this}.setViewControllersAnimated([${viewController}], ${animated}); depth = ${navDepth}`, traceCategories.Navigation); } - return; - } + // We should hide the current entry from the back stack. + if (!Frame._isEntryBackstackVisible(this._currentEntry)) { + let newControllers = NSMutableArray.alloc().initWithArray(this._ios.controller.viewControllers); + if (newControllers.count === 0) { + throw new Error("Wrong controllers count."); + } - // We should hide the current entry from the back stack. - if (!Frame._isEntryBackstackVisible(this._currentEntry)) { - let newControllers = NSMutableArray.alloc().initWithArray(this._ios.controller.viewControllers); - if (newControllers.count === 0) { - throw new Error("Wrong controllers count."); - } + // the code below fixes a phantom animation that appears on the Back button in this case + // TODO: investigate why the animation happens at first place before working around it + viewController.navigationItem.hidesBackButton = this.backStack.length === 0; - // the code below fixes a phantom animation that appears on the Back button in this case - // TODO: investigate why the animation happens at first place before working around it - viewController.navigationItem.hidesBackButton = this.backStack.length === 0; + // swap the top entry with the new one + const skippedNavController = newControllers.lastObject; + (skippedNavController).isBackstackSkipped = true; + newControllers.removeLastObject(); + newControllers.addObject(viewController); - // swap the top entry with the new one - const skippedNavController = newControllers.lastObject; - (skippedNavController).isBackstackSkipped = true; - newControllers.removeLastObject(); - newControllers.addObject(viewController); + // replace the controllers instead of pushing directly + this._ios.controller.setViewControllersAnimated(newControllers, animated); + if (traceEnabled()) { + traceWrite(`${this}.setViewControllersAnimated([originalControllers - lastController + ${viewController}], ${animated}); depth = ${navDepth}`, traceCategories.Navigation); + } + return; + } - // replace the controllers instead of pushing directly - this._ios.controller.setViewControllersAnimated(newControllers, animated); + // General case. + this._ios.controller.pushViewControllerAnimated(viewController, animated); if (traceEnabled()) { - traceWrite(`${this}.setViewControllersAnimated([originalControllers - lastController + ${viewController}], ${animated}); depth = ${navDepth}`, traceCategories.Navigation); + traceWrite(`${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, traceCategories.Navigation); } - return; - } - - // General case. - this._ios.controller.pushViewControllerAnimated(viewController, animated); - if (traceEnabled()) { - traceWrite(`${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, traceCategories.Navigation); } } public _goBackCore(backstackEntry: BackstackEntry) { super._goBackCore(backstackEntry); - navDepth = backstackEntry[NAV_DEPTH]; + if (backstackEntry) { + navDepth = backstackEntry[NAV_DEPTH]; - if (!this._shouldSkipNativePop) { - let controller = backstackEntry.resolvedPage.ios; - let animated = this._currentEntry ? this._getIsAnimatedNavigation(this._currentEntry.entry) : false; + if (!this._shouldSkipNativePop) { + let controller = backstackEntry.resolvedPage.ios; + let animated = this._currentEntry ? this._getIsAnimatedNavigation(this._currentEntry.entry) : false; - this._updateActionBar(backstackEntry.resolvedPage); - if (traceEnabled()) { - traceWrite(`${this}.popToViewControllerAnimated(${controller}, ${animated}); depth = ${navDepth}`, traceCategories.Navigation); - } - this._ios.controller.popToViewControllerAnimated(controller, animated); + this._updateActionBar(backstackEntry.resolvedPage); + if (traceEnabled()) { + traceWrite(`${this}.popToViewControllerAnimated(${controller}, ${animated}); depth = ${navDepth}`, traceCategories.Navigation); + } + this._ios.controller.popToViewControllerAnimated(controller, animated); + } } + } public _updateActionBar(page?: Page, disableNavBarAnimation: boolean = false): void { diff --git a/tns-core-modules/ui/gestures/gestures.ios.ts b/tns-core-modules/ui/gestures/gestures.ios.ts index 45d397e5c6..afbc0ab712 100644 --- a/tns-core-modules/ui/gestures/gestures.ios.ts +++ b/tns-core-modules/ui/gestures/gestures.ios.ts @@ -198,7 +198,11 @@ export class GesturesObserver extends GesturesObserverBase { public _executeCallback(args: GestureEventData) { if (this.callback) { - this.callback.call(this.context, args); + try { + this.callback.call(this.context, args); + } catch (e) { + // TODO + } } }