From b615c60478180d65af5bd54d84c706afdc1b36d9 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Wed, 29 Jun 2016 00:27:50 -0500 Subject: [PATCH] fix(loading): fix loading overlay during app init Closes #6209 --- src/components/nav/nav-controller.ts | 53 ++++++++----- .../nav/test/nav-controller.spec.ts | 75 +++++++++++++++---- src/components/nav/view-controller.ts | 2 +- 3 files changed, 99 insertions(+), 31 deletions(-) diff --git a/src/components/nav/nav-controller.ts b/src/components/nav/nav-controller.ts index fda6318943..b2ea2b5899 100644 --- a/src/components/nav/nav-controller.ts +++ b/src/components/nav/nav-controller.ts @@ -831,6 +831,10 @@ export class NavController extends Ion { // it should be removed after the transition view.state = STATE_REMOVE_AFTER_TRANS; + } else if (view.state === STATE_INIT_ENTER) { + // asked to be removed before it even entered! + view.state = STATE_CANCEL_ENTER; + } else { // if this view is already leaving then no need to immediately // remove it, otherwise set the remove state @@ -1087,9 +1091,9 @@ export class NavController extends Ion { // create the transitions animation, play the animation // when the transition ends call wait for it to end - if (enteringView.state === STATE_INACTIVE) { - // this entering view is already set to inactive, so this - // transition must be canceled, so don't continue + if (enteringView.state === STATE_INACTIVE || enteringView.state === STATE_CANCEL_ENTER) { + // this entering view is already set to inactive or has been canceled + // so this transition must not begin, so don't continue return done(); } @@ -1185,9 +1189,10 @@ export class NavController extends Ion { this._app.viewDidEnter.emit(enteringView); } - if (enteringView.fireOtherLifecycles) { + if (enteringView.fireOtherLifecycles && this._init) { // only fire leaving lifecycle if the entering // view hasn't explicitly set not to + // and after the nav has initialized leavingView.fireDidLeave(); this.viewDidLeave.emit(leavingView); this._app.viewDidLeave.emit(leavingView); @@ -1224,6 +1229,11 @@ export class NavController extends Ion { // a transition has completed, but not sure if it's the last one or not // check if this transition is the most recent one or not + if (enteringView.state === STATE_CANCEL_ENTER) { + // this view was told to leave before it finished entering + this.remove(enteringView.index, 1); + } + if (transId === this._transIds) { // ok, good news, there were no other transitions that kicked // off during the time this transition started and ended @@ -1263,9 +1273,7 @@ export class NavController extends Ion { // this check only needs to happen once, which will add the css // class to the nav when it's finished its first transition - if (!this._init) { - this._init = true; - } + this._init = true; } else { // this transition has not completed, meaning the @@ -1406,6 +1414,14 @@ export class NavController extends Ion { this._compiler.resolveComponent(view.componentType).then(componentFactory => { + if (view.state === STATE_CANCEL_ENTER) { + // view may have already been removed from the stack + // if so, don't even bother adding it + view.destroy(); + this._views.splice(view.index, 1); + return; + } + // add more providers to just this page let componentProviders = ReflectiveInjector.resolve([ provide(NavController, {useValue: this}), @@ -1613,7 +1629,7 @@ export class NavController extends Ion { /** * @private */ - getByState(state: string): ViewController { + getByState(state: number): ViewController { for (var i = this._views.length - 1; i >= 0; i--) { if (this._views[i].state === state) { return this._views[i]; @@ -1708,6 +1724,7 @@ export class NavController extends Ion { /** * @private + * Dismiss all pages which have set the `dismissOnPageChange` property. */ dismissPageChangeViews() { this._views.forEach(view => { @@ -1765,15 +1782,17 @@ export class NavController extends Ion { } -const STATE_ACTIVE = 'active'; -const STATE_INACTIVE = 'inactive'; -const STATE_INIT_ENTER = 'init_enter'; -const STATE_INIT_LEAVE = 'init_leave'; -const STATE_TRANS_ENTER = 'trans_enter'; -const STATE_TRANS_LEAVE = 'trans_leave'; -const STATE_REMOVE = 'remove'; -const STATE_REMOVE_AFTER_TRANS = 'remove_after_trans'; -const STATE_FORCE_ACTIVE = 'force_active'; +const STATE_ACTIVE = 1; +const STATE_INACTIVE = 2; +const STATE_INIT_ENTER = 3; +const STATE_INIT_LEAVE = 4; +const STATE_TRANS_ENTER = 5; +const STATE_TRANS_LEAVE = 6; +const STATE_REMOVE = 7; +const STATE_REMOVE_AFTER_TRANS = 8; +const STATE_CANCEL_ENTER = 9; +const STATE_FORCE_ACTIVE = 10; + const INIT_ZINDEX = 100; const PORTAL_ZINDEX = 9999; diff --git a/src/components/nav/test/nav-controller.spec.ts b/src/components/nav/test/nav-controller.spec.ts index 2f6e0f4771..c81213f3cf 100644 --- a/src/components/nav/test/nav-controller.spec.ts +++ b/src/components/nav/test/nav-controller.spec.ts @@ -137,15 +137,17 @@ export function run() { nav.views = [view1, view2, view3]; nav._remove(1, 1); - expect(nav.length()).toBe(2); + expect(nav.length()).toBe(3); expect(view1.state).toBe(STATE_INIT_ENTER); - expect(view2.state).toBe(STATE_REMOVE); + expect(view2.state).toBe(STATE_CANCEL_ENTER); expect(view3.state).toBe(STATE_INIT_LEAVE); expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER); expect(nav.getByIndex(0).componentType).toBe(Page1); - expect(nav.getByIndex(1).state).toBe(STATE_INIT_LEAVE); - expect(nav.getByIndex(1).componentType).toBe(Page3); + expect(nav.getByIndex(1).state).toBe(STATE_CANCEL_ENTER); + expect(nav.getByIndex(1).componentType).toBe(Page2); + expect(nav.getByIndex(2).state).toBe(STATE_INIT_LEAVE); + expect(nav.getByIndex(2).componentType).toBe(Page3); }); it('should set to pop the active and enter the previous', () => { @@ -728,6 +730,7 @@ export function run() { spyOn(enteringView, 'fireDidEnter'); spyOn(leavingView, 'fireDidLeave'); + nav._init = true; nav._afterTrans(enteringView, leavingView, navOpts, hasCompleted, done); expect(enteringView.fireDidEnter).toHaveBeenCalled(); @@ -748,6 +751,7 @@ export function run() { spyOn(enteringView, 'fireDidEnter'); spyOn(leavingView, 'fireDidLeave'); + nav._init = true; nav._afterTrans(enteringView, leavingView, navOpts, hasCompleted, done); expect(enteringView.fireDidEnter).not.toHaveBeenCalled(); @@ -788,6 +792,7 @@ export function run() { spyOn(enteringView, 'fireDidEnter'); spyOn(leavingView, 'fireDidLeave'); + nav._init = true; nav._afterTrans(enteringView, leavingView, navOpts, hasCompleted, done); expect(enteringView.fireDidEnter).not.toHaveBeenCalled(); @@ -817,6 +822,19 @@ export function run() { describe('_transFinish', () => { + it('should remove entering view if it was already set to cancel', () => { + let enteringView = new ViewController(Page1); + let leavingView = new ViewController(Page2); + enteringView.state = STATE_CANCEL_ENTER; + + spyOn(nav, 'remove'); + + nav._transFinish(1, enteringView, leavingView, 'forward', true); + + expect(nav.remove).toHaveBeenCalled(); + expect(enteringView.state).toBe(STATE_CANCEL_ENTER); + }); + it('should not entering/leaving state, after transition that isnt the most recent, and state already changed', () => { let enteringView = new ViewController(Page1); enteringView.state = 'somethingelse'; @@ -1492,6 +1510,36 @@ export function run() { // act nav._beforeTrans(view1, view2, {}, () => {}); }); + + it('should not begin transition when entering stated is inactive', () => { + let view1 = new ViewController(Page1); + view1.state = STATE_INACTIVE; + + let wasDoneCalled = false; + let done = () => { + wasDoneCalled = true; + }; + + nav._beforeTrans(view1, null, {}, done); + + expect(wasDoneCalled).toEqual(true); + expect(view1.state).toEqual(STATE_INACTIVE); + }); + + it('should not begin transition when entering state is canceled', () => { + let view1 = new ViewController(Page1); + view1.state = STATE_CANCEL_ENTER; + + let wasDoneCalled = false; + let done = () => { + wasDoneCalled = true; + }; + + nav._beforeTrans(view1, null, {}, done); + + expect(wasDoneCalled).toEqual(true); + expect(view1.state).toEqual(STATE_CANCEL_ENTER); + }); }); /* private method */ @@ -1679,12 +1727,13 @@ class MockNavController extends NavController { } -const STATE_ACTIVE = 'active'; -const STATE_INACTIVE = 'inactive'; -const STATE_INIT_ENTER = 'init_enter'; -const STATE_INIT_LEAVE = 'init_leave'; -const STATE_TRANS_ENTER = 'trans_enter'; -const STATE_TRANS_LEAVE = 'trans_leave'; -const STATE_REMOVE = 'remove'; -const STATE_REMOVE_AFTER_TRANS = 'remove_after_trans'; -const STATE_FORCE_ACTIVE = 'force_active'; +const STATE_ACTIVE = 1; +const STATE_INACTIVE = 2; +const STATE_INIT_ENTER = 3; +const STATE_INIT_LEAVE = 4; +const STATE_TRANS_ENTER = 5; +const STATE_TRANS_LEAVE = 6; +const STATE_REMOVE = 7; +const STATE_REMOVE_AFTER_TRANS = 8; +const STATE_CANCEL_ENTER = 9; +const STATE_FORCE_ACTIVE = 10; diff --git a/src/components/nav/view-controller.ts b/src/components/nav/view-controller.ts index a1f18e694d..51054290ab 100644 --- a/src/components/nav/view-controller.ts +++ b/src/components/nav/view-controller.ts @@ -66,7 +66,7 @@ export class ViewController { /** * @private */ - state: string = ''; + state: number = 0; /** * @private