diff --git a/apps/automated/src/ui/page/page-tests-common.ts b/apps/automated/src/ui/page/page-tests-common.ts index 00f5035d8..d33ca95dc 100644 --- a/apps/automated/src/ui/page/page-tests-common.ts +++ b/apps/automated/src/ui/page/page-tests-common.ts @@ -181,7 +181,7 @@ function _test_PageNavigation_EventSequence(withTransition: boolean) { helper.navigateWithEntry(navigationEntry); helper.goBack(); - const expectedEventSequence = ['navigatingTo', 'loaded', 'navigatedTo', 'navigatingFrom', 'unloaded', 'navigatedFrom']; + const expectedEventSequence = ['navigatingTo', 'loaded', 'navigatedTo', 'navigatingFrom', 'navigatedFrom', 'unloaded']; TKUnit.arrayAssert(eventSequence, expectedEventSequence, 'Actual event sequence is not equal to expected. Actual: ' + eventSequence + '; Expected: ' + expectedEventSequence); } diff --git a/packages/core/ui/frame/fragment.transitions.android.ts b/packages/core/ui/frame/fragment.transitions.android.ts index 6fdc9bb13..04f8ec9b2 100644 --- a/packages/core/ui/frame/fragment.transitions.android.ts +++ b/packages/core/ui/frame/fragment.transitions.android.ts @@ -26,6 +26,7 @@ let AnimationListener: android.animation.Animator.AnimatorListener; interface ExpandedTransitionListener extends androidx.transition.Transition.TransitionListener { entry: ExpandedEntry; + backEntry?: BackstackEntry; transition: androidx.transition.Transition; } @@ -143,7 +144,7 @@ export function _setAndroidFragmentTransitions(animated: boolean, navigationTran if (currentFragmentNeedsDifferentAnimation) { setupCurrentFragmentFadeTransition(navigationTransition, currentEntry); } - } else if (name === 'explode') { + } else if (name === 'explode') { setupNewFragmentExplodeTransition(navigationTransition, newEntry); if (currentFragmentNeedsDifferentAnimation) { setupCurrentFragmentExplodeTransition(navigationTransition, currentEntry); @@ -223,6 +224,7 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener { onAnimationStart(animator: ExpandedAnimator): void { const entry = animator.entry; + const backEntry = animator.backEntry; addToWaitingQueue(entry); if (Trace.isEnabled()) { Trace.write(`START ${animator.transitionType} for ${entry.fragmentTag}`, Trace.categories.Transition); @@ -236,10 +238,13 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener { } onAnimationEnd(animator: ExpandedAnimator): void { + const entry = animator.entry; + const backEntry = animator.backEntry; if (Trace.isEnabled()) { - Trace.write(`END ${animator.transitionType} for ${animator.entry.fragmentTag}`, Trace.categories.Transition); + Trace.write(`END ${animator.transitionType} for ${entry.fragmentTag} backEntry:${backEntry ? backEntry.fragmentTag : 'none'}`, Trace.categories.Transition); } - transitionOrAnimationCompleted(animator.entry, animator.backEntry); + transitionOrAnimationCompleted(entry, backEntry); + animator.backEntry = null; } onAnimationCancel(animator: ExpandedAnimator): void { @@ -345,10 +350,12 @@ function getTransitionListener(entry: ExpandedEntry, transition: androidx.transi onTransitionEnd(transition: androidx.transition.Transition): void { const entry = this.entry; + const backEntry = this.backEntry; if (Trace.isEnabled()) { - Trace.write(`END ${toShortString(transition)} transition for ${entry.fragmentTag}`, Trace.categories.Transition); + Trace.write(`END ${toShortString(transition)} transition for ${entry.fragmentTag} backEntry:${backEntry ? backEntry.fragmentTag : 'none'}`, Trace.categories.Transition); } - transitionOrAnimationCompleted(entry, this.backEntry); + transitionOrAnimationCompleted(entry, backEntry); + this.backEntry = null; } onTransitionResume(transition: androidx.transition.Transition): void { @@ -660,6 +667,7 @@ function transitionOrAnimationCompleted(entry: ExpandedEntry, backEntry: Backsta if (!entries) { return; } + console.log('transitionOrAnimationCompleted', frameId, backEntry && backEntry.fragmentTag, waitingQueue.size, entries.size, completedEntries.size ); entries.delete(entry); if (entries.size === 0) { diff --git a/packages/core/ui/frame/frame-common.ts b/packages/core/ui/frame/frame-common.ts index 64a82c684..0e1ec2b3f 100644 --- a/packages/core/ui/frame/frame-common.ts +++ b/packages/core/ui/frame/frame-common.ts @@ -266,8 +266,8 @@ export class FrameBase extends CustomLayoutView { public _updateBackstack(entry: BackstackEntry, navigationType: NavigationType): void { const isBack = navigationType === NavigationType.back; const isReplace = navigationType === NavigationType.replace; - this.raiseCurrentPageNavigatedEvents(isBack); const current = this._currentEntry; + this.raiseCurrentPageNavigatedEvents(isBack); // Do nothing for Hot Module Replacement if (isBack) { @@ -303,10 +303,6 @@ export class FrameBase extends CustomLayoutView { private raiseCurrentPageNavigatedEvents(isBack: boolean) { const page = this.currentPage; if (page) { - if (page.isLoaded) { - // Forward navigation does not remove page from frame so we raise unloaded manually. - page.callUnloaded(); - } page.onNavigatedFrom(isBack); } } diff --git a/packages/core/ui/frame/index.android.ts b/packages/core/ui/frame/index.android.ts index a7ae9ee9a..8b2aa4849 100644 --- a/packages/core/ui/frame/index.android.ts +++ b/packages/core/ui/frame/index.android.ts @@ -19,6 +19,7 @@ import { Builder } from '../builder'; import { CSSUtils } from '../../css/system-classes'; import { Device } from '../../platform'; import { profile } from '../../profiling'; +import { ExpandedEntry } from './fragment.transitions.android'; export * from './frame-common'; @@ -325,6 +326,8 @@ export class Frame extends FrameBase { // If we had real navigation process queue. this._processNavigationQueue(entry.resolvedPage); + + } else { // Otherwise currentPage was recreated so this wasn't real navigation. // Continue with next item in the queue. @@ -437,7 +440,14 @@ export class Frame extends FrameBase { //transaction.setTransition(androidx.fragment.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN); } - transaction.replace(this.containerViewId, newFragment, newFragmentTag); + if (clearHistory || isReplace) { + transaction.replace(this.containerViewId, newFragment, newFragmentTag); + } else { + transaction.add(this.containerViewId, newFragment, newFragmentTag); + } + if (this._currentEntry && this._currentEntry.entry.backstackVisible === false) { + transaction.remove(this._currentEntry.fragment); + } transaction.commitAllowingStateLoss(); } @@ -459,8 +469,26 @@ export class Frame extends FrameBase { _reverseTransitions(backstackEntry, this._currentEntry); - transaction.replace(this.containerViewId, backstackEntry.fragment, backstackEntry.fragmentTag); - + const currentIndex =this.backStack.length; + const goBackToIndex = this.backStack.indexOf(backstackEntry); + + // the order is important so that the transition listener called be + // the one from the current entry we are going back from + if (this._currentEntry !== backstackEntry) { + const entry = this._currentEntry as ExpandedEntry; + // if we are going back we need to store where we are backing to + // so that we can set the current entry + // it only needs to be done on the return transition + if (entry.returnTransitionListener) { + entry.returnTransitionListener.backEntry = backstackEntry; + } + + transaction.remove((this._currentEntry).fragment); + } + for (let index = goBackToIndex + 1; index < currentIndex; index++) { + transaction.remove(this.backStack[index].fragment); + } + transaction.commitAllowingStateLoss(); } @@ -752,6 +780,12 @@ function findPageForFragment(fragment: androidx.fragment.app.Fragment, frame: Fr entry = current; } else if (executingContext && executingContext.entry && executingContext.entry.fragmentTag === fragmentTag) { entry = executingContext.entry; + } else { + frame.backStack.forEach(e=>{ + if (e && e.fragmentTag === fragmentTag) { + entry = e; + } + }) } let page: Page;