Skip to content

Commit 0aca087

Browse files
authored
fix(hmr): quick fade upon replace navigation (#7251)
1 parent d60e5da commit 0aca087

6 files changed

Lines changed: 58 additions & 20 deletions

File tree

tests/app/livesync/livesync-tests.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,5 @@ function _test_onLiveSync_ModuleContext_TypeStyle(context: { type, path }) {
146146
}
147147

148148
function waitUntilLivesyncComplete(frame: Frame) {
149-
if (isAndroid) {
150-
TKUnit.waitUntilReady(() => frame._executingEntry === null);
151-
} else {
152-
TKUnit.waitUntilReady(() => frame.currentPage.isLoaded);
153-
}
149+
TKUnit.waitUntilReady(() => frame._executingEntry === null);
154150
}

tns-core-modules/ui/core/view/view-common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
} from ".";
66

77
import {
8-
ViewBase, Property, booleanConverter, eachDescendant, EventData, layout,
8+
ViewBase, Property, booleanConverter, EventData, layout,
99
getEventOrGestureName, traceEnabled, traceWrite, traceCategories,
1010
InheritedProperty, ShowModalOptions
1111
} from "../view-base";

tns-core-modules/ui/frame/fragment.transitions.android.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,11 @@ export function _setAndroidFragmentTransitions(
169169

170170
// Having transition means we have custom animation
171171
if (transition) {
172-
// we do not use Android backstack so setting popEnter / popExit is meaningless (3rd and 4th optional args)
173-
fragmentTransaction.setCustomAnimations(AnimationType.enterFakeResourceId, AnimationType.exitFakeResourceId);
172+
if (fragmentTransaction) {
173+
// we do not use Android backstack so setting popEnter / popExit is meaningless (3rd and 4th optional args)
174+
fragmentTransaction.setCustomAnimations(AnimationType.enterFakeResourceId, AnimationType.exitFakeResourceId);
175+
}
176+
174177
setupAllAnimation(newEntry, transition);
175178
if (currentFragmentNeedsDifferentAnimation) {
176179
setupExitAndPopEnterAnimation(currentEntry, transition);
@@ -502,6 +505,8 @@ function clearEntry(entry: ExpandedEntry, removeListener: boolean): void {
502505
clearAnimationListener(entry.exitAnimator, listener);
503506
clearAnimationListener(entry.popEnterAnimator, listener);
504507
clearAnimationListener(entry.popExitAnimator, listener);
508+
clearAnimationListener(entry.defaultEnterAnimator, listener);
509+
clearAnimationListener(entry.defaultExitAnimator, listener);
505510
}
506511
}
507512

tns-core-modules/ui/frame/frame.android.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// Definitions.
22
import {
33
AndroidFrame as AndroidFrameDefinition, AndroidActivityCallbacks,
4-
AndroidFragmentCallbacks, BackstackEntry, NavigationTransition
4+
AndroidFragmentCallbacks, BackstackEntry, NavigationTransition, NavigationEntry
55
} from ".";
66
import { Page } from "../page";
77

88
// Types.
99
import * as application from "../../application";
1010
import {
11-
FrameBase, goBack, stack, NavigationContext, NavigationType,
11+
FrameBase, goBack, stack, NavigationType,
1212
Observable, View, traceCategories, traceEnabled, traceError, traceWrite
1313
} from "./frame-common";
1414

@@ -21,7 +21,6 @@ import { profile } from "../../profiling";
2121

2222
// TODO: Remove this and get it from global to decouple builder for angular
2323
import { createViewFromEntry } from "../builder";
24-
import { getModuleName } from "../../utils/utils";
2524

2625
export * from "./frame-common";
2726

@@ -37,6 +36,7 @@ const INTENT_EXTRA = "com.tns.activity";
3736
const ROOT_VIEW_ID_EXTRA = "com.tns.activity.rootViewId";
3837
const FRAMEID = "_frameId";
3938
const CALLBACKS = "_callbacks";
39+
const HMR_REPLACE_TRANSITION = "fade";
4040

4141
const ownerSymbol = Symbol("_owner");
4242
const activityRootViewsMap = new Map<number, WeakRef<View>>();
@@ -319,6 +319,18 @@ export class Frame extends FrameBase {
319319
restoreAnimatorState(this._currentEntry, this._cachedAnimatorState);
320320
this._cachedAnimatorState = null;
321321
}
322+
323+
// restore original fragment transitions if we just completed replace navigation (hmr)
324+
if (navigationType === NavigationType.replace) {
325+
_clearEntry(entry);
326+
327+
const animated = entry.entry.animated;
328+
const navigationTransition = this._getNavigationTransition(entry.entry);
329+
const currentEntry = null;
330+
const newEntry = entry;
331+
const transaction = null;
332+
_setAndroidFragmentTransitions(animated, navigationTransition, currentEntry, newEntry, transaction, this._android.frameId);
333+
}
322334
}
323335

324336
public onBackPressed(): boolean {
@@ -381,12 +393,20 @@ export class Frame extends FrameBase {
381393
const newFragmentTag = `fragment${fragmentId}[${navDepth}]`;
382394
const newFragment = this.createFragment(newEntry, newFragmentTag);
383395
const transaction = manager.beginTransaction();
384-
const animated = currentEntry ? this._getIsAnimatedNavigation(newEntry.entry) : false;
396+
let animated = currentEntry ? this._getIsAnimatedNavigation(newEntry.entry) : false;
385397
// NOTE: Don't use transition for the initial navigation (same as on iOS)
386398
// On API 21+ transition won't be triggered unless there was at least one
387399
// layout pass so we will wait forever for transitionCompleted handler...
388400
// https://github.com/NativeScript/NativeScript/issues/4895
389-
const navigationTransition = this._currentEntry ? this._getNavigationTransition(newEntry.entry) : null;
401+
let navigationTransition: NavigationTransition;
402+
if (isReplace) {
403+
animated = true;
404+
navigationTransition = { name: HMR_REPLACE_TRANSITION, duration: 100 };
405+
} else if (this._currentEntry) {
406+
navigationTransition = this._getNavigationTransition(newEntry.entry);
407+
} else {
408+
navigationTransition = null;
409+
}
390410

391411
_setAndroidFragmentTransitions(animated, navigationTransition, currentEntry, newEntry, transaction, this._android.frameId);
392412

tns-core-modules/ui/frame/frame.ios.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import { profile } from "../../profiling";
77

88
//Types.
99
import {
10-
FrameBase, View, isCategorySet, layout, NavigationContext,
10+
FrameBase, View, isCategorySet, layout,
1111
NavigationType, traceCategories, traceEnabled, traceWrite
1212
} from "./frame-common";
1313
import { _createIOSAnimatedTransitioning } from "./fragment.transitions";
1414

15-
import { createViewFromEntry } from "../builder";
1615
import * as utils from "../../utils/utils";
1716

1817
export * from "./frame-common";
@@ -24,6 +23,7 @@ const DELEGATE = "_delegate";
2423
const NAV_DEPTH = "_navDepth";
2524
const TRANSITION = "_transition";
2625
const NON_ANIMATED_TRANSITION = "non-animated";
26+
const HMR_REPLACE_TRANSITION = "fade";
2727

2828
let navDepth = -1;
2929

@@ -88,13 +88,16 @@ export class Frame extends FrameBase {
8888

8989
let navigationTransition: NavigationTransition;
9090
let animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false;
91-
if (animated) {
91+
if (isReplace) {
92+
animated = true;
93+
navigationTransition = { name: HMR_REPLACE_TRANSITION, duration: 100 }
94+
viewController[TRANSITION] = navigationTransition;
95+
} else if (animated) {
9296
navigationTransition = this._getNavigationTransition(backstackEntry.entry);
9397
if (navigationTransition) {
9498
viewController[TRANSITION] = navigationTransition;
9599
}
96-
}
97-
else {
100+
} else {
98101
//https://github.com/NativeScript/NativeScript/issues/1787
99102
viewController[TRANSITION] = { name: NON_ANIMATED_TRANSITION };
100103
}

tns-core-modules/ui/page/page.ios.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Definitions.
2-
import { Frame } from "../frame";
2+
import { Frame, BackstackEntry } from "../frame";
33
import { NavigationType } from "../frame/frame-common";
44

55
// Types.
@@ -15,6 +15,8 @@ export * from "./page-common";
1515

1616
const ENTRY = "_entry";
1717
const DELEGATE = "_delegate";
18+
const TRANSITION = "_transition";
19+
const NON_ANIMATED_TRANSITION = "non-animated";
1820

1921
const majorVersion = iosUtils.MajorVersion;
2022

@@ -130,7 +132,7 @@ class UIViewControllerImpl extends UIViewController {
130132
const frame = navigationController ? (<any>navigationController).owner : null;
131133
// Skip navigation events if modal page is shown.
132134
if (!owner._presentedViewController && frame) {
133-
const newEntry = this[ENTRY];
135+
const newEntry: BackstackEntry = this[ENTRY];
134136

135137
let isBack: boolean;
136138
let navType = frame.navigationType;
@@ -146,6 +148,18 @@ class UIViewControllerImpl extends UIViewController {
146148
}
147149

148150
frame.setCurrent(newEntry, navType);
151+
152+
if (frame.navigationType === NavigationType.replace) {
153+
let controller = newEntry.resolvedPage.ios;
154+
if (controller) {
155+
if (newEntry.entry.animated) {
156+
controller[TRANSITION] = frame._getNavigationTransition(newEntry.entry);
157+
} else {
158+
controller[TRANSITION] = { name: NON_ANIMATED_TRANSITION };
159+
}
160+
}
161+
}
162+
149163
frame.navigationType = isBack ? NavigationType.back : NavigationType.forward;
150164

151165
// If page was shown with custom animation - we need to set the navigationController.delegate to the animatedDelegate.

0 commit comments

Comments
 (0)