Skip to content

Commit 70f0112

Browse files
ADjenkovSvetoslavTsenov
authored andcommitted
feat(frame): handle back navigation when common layout is used as a root element (NativeScript#5608)
* test(e2e): update modal navigation app Add layout as root. Add show modal layout. * chore(frame): move frame stack modifiers in a separate frame-stack module * feat(frame): handle back navigation when using common layout as root element
1 parent 8a1958e commit 70f0112

File tree

12 files changed

+161
-48
lines changed

12 files changed

+161
-48
lines changed

e2e/modal-navigation/app/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ import * as application from "tns-core-modules/application";
33

44
application.run({ moduleName: "app-root" });
55
// application.run({ moduleName: "tab-root" });
6+
// application.run({ moduleName: "layout-root" });

e2e/modal-navigation/app/home/home-page.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ export function onModalPage(args: EventData) {
4141
false);
4242
}
4343

44+
export function onModalLayout(args: EventData) {
45+
const view = args.object as View;
46+
view.showModal("modal-layout/modal-layout",
47+
"context",
48+
() => console.log("home-page modal layout closed"),
49+
false);
50+
}
51+
4452
export function onModalTabView(args: EventData) {
4553
const fullscreen = false;
4654
const animated = false;
@@ -61,7 +69,14 @@ export function onNavigate(args: EventData) {
6169
page.frame.navigate("second/second-page");
6270
}
6371

64-
export function onRootViewChange() {
65-
let rootView = application.getRootView();
66-
rootView instanceof Frame ? application._resetRootView({ moduleName: "tab-root" }) : application._resetRootView({ moduleName: "app-root" });
72+
export function onFrameRootViewReset() {
73+
application._resetRootView({ moduleName: "app-root" });
74+
}
75+
76+
export function onTabRootViewReset() {
77+
application._resetRootView({ moduleName: "tab-root" });
6778
}
79+
80+
export function onLayoutRootViewReset() {
81+
application._resetRootView({ moduleName: "layout-root" });
82+
}

e2e/modal-navigation/app/home/home-page.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@
1212
<StackLayout>
1313
<Button text="Show Modal Page With Frame" tap="onModalFrame" />
1414
<Button text="Show Modal Page" tap="onModalPage" />
15+
<Button text="Show Modal Layout" tap="onModalLayout" />
1516
<Button text="Show Modal TabView" tap="onModalTabView" />
1617
<Button text="Navigate To Second Page" tap="onNavigate" />
17-
<Button text="Change Root View" tap="onRootViewChange" />
18+
<Button text="Reset Frame Root View" tap="onFrameRootViewReset" />
19+
<Button text="Reset Tab Root View" tap="onTabRootViewReset" />
20+
<Button text="Reset Layout Root View" tap="onLayoutRootViewReset" />
1821
</StackLayout>
1922
</Page>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<GridLayout>
2+
<Frame defaultPage="home/home-page" />
3+
</GridLayout>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export function onShowingModally() {
2+
console.log("modal-layout showingModally");
3+
}
4+
5+
export function onLoaded() {
6+
console.log("modal-layout loaded");
7+
}
8+
9+
export function onNavigatingTo() {
10+
console.log("modal-layout onNavigatingTo");
11+
}
12+
13+
export function onNavigatingFrom() {
14+
console.log("modal-layout onNavigatingFrom");
15+
}
16+
17+
export function onNavigatedTo() {
18+
console.log("modal-layout onNavigatedTo");
19+
}
20+
21+
export function onNavigatedFrom() {
22+
console.log("modal-layout onNavigatedFrom");
23+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<GridLayout backgroundColor="green" showingModally="onShowingModally" loaded="onLoaded"
2+
navigatingTo="onNavigatingTo"
3+
navigatingFrom="onNavigatingFrom"
4+
navigatedTo="onNavigatedTo"
5+
navigatedFrom="onNavigatedFrom">
6+
<Frame defaultPage="modal/modal-page"></Frame>
7+
</GridLayout>

e2e/modal-navigation/e2e/screen.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ const modalFrame = "Show Modal Page With Frame";
1212
const modalPage = "Show Modal Page";
1313
const modalTabView = "Show Modal TabView";
1414
const navToSecondPage = "Navigate To Second Page";
15-
const rootView = "Change Root View";
15+
const resetFrameRootView = "Reset Frame Root View";
16+
const resetTabRootView = "Reset Tab Root View";
17+
const resetLayoutRootView = "Reset Layout Root View";
1618

1719
const showNestedModalFrame = "Show Nested Modal Page With Frame";
1820
const showNestedModalPage = "Show Nested Modal Page";
@@ -35,9 +37,19 @@ export class Screen {
3537
console.log(home + " loaded!");
3638
}
3739

38-
changeRootView = async () => {
39-
const btnChangeRootView = await this._driver.findElementByText(rootView);
40-
await btnChangeRootView.tap();
40+
resetFrameRootView = async () => {
41+
const btnResetFrameRootView = await this._driver.findElementByText(resetFrameRootView);
42+
await btnResetFrameRootView.tap();
43+
}
44+
45+
resetTabRootView = async () => {
46+
const btnResetTabRootView = await this._driver.findElementByText(resetTabRootView);
47+
await btnResetTabRootView.tap();
48+
}
49+
50+
resetLayoutRootView = async () => {
51+
const btnResetLayoutRootView = await this._driver.findElementByText(resetLayoutRootView);
52+
await btnResetLayoutRootView.tap();
4153
}
4254

4355
loadedTabRootView = async () => {
@@ -52,7 +64,7 @@ export class Screen {
5264
try {
5365
await this.loadedTabRootView();
5466
} catch (err) {
55-
await this.changeRootView();
67+
await this.resetTabRootView();
5668
await this.loadedTabRootView();
5769
}
5870
}

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
263263
that._closeModalCallback = null;
264264
that._dialogClosed();
265265
parent._modal = null;
266-
266+
267267
if (typeof closeCallback === "function") {
268268
closeCallback.apply(undefined, arguments);
269269
}
@@ -976,6 +976,18 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
976976
_onDetachedFromWindow(): void {
977977
//
978978
}
979+
980+
_hasAncestorView(ancestorView: ViewDefinition): boolean {
981+
let matcher = (view: ViewDefinition) => view === ancestorView;
982+
983+
for (let parent = this.parent; parent != null; parent = parent.parent) {
984+
if (matcher(<ViewDefinition>parent)) {
985+
return true;
986+
}
987+
}
988+
989+
return false;
990+
}
979991
}
980992

981993
export const automationTextProperty = new Property<ViewCommon, string>({ name: "automationText" });

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222

2323
import { Background, ad as androidBackground } from "../../styling/background";
2424
import { profile } from "../../../profiling";
25+
import { topmost } from "../../frame/frame-stack";
2526

2627
export * from "./view-common";
2728

@@ -287,6 +288,18 @@ export class View extends ViewCommon {
287288
super.onUnloaded();
288289
}
289290

291+
public onBackPressed(): boolean {
292+
let topmostFrame = topmost();
293+
294+
// Delegate back navigation handling to the topmost Frame
295+
// when it's a child of the current View.
296+
if (topmostFrame && topmostFrame._hasAncestorView(this)) {
297+
return topmostFrame.onBackPressed();
298+
}
299+
300+
return false;
301+
}
302+
290303
private hasGestureObservers() {
291304
return this._gestureObservers && Object.keys(this._gestureObservers).length > 0
292305
}

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export abstract class View extends ViewBase {
110110
* String value used when hooking to shownModally event.
111111
*/
112112
public static shownModallyEvent: string;
113-
113+
114114
/**
115115
* Gets the android-specific native instance that lies behind this proxy. Will be available if running on an Android platform.
116116
*/
@@ -705,6 +705,11 @@ export abstract class View extends ViewBase {
705705
* Called in android when native view is dettached from window.
706706
*/
707707
_onDetachedFromWindow(): void;
708+
709+
/**
710+
* Checks whether the current view has specific view for an ancestor.
711+
*/
712+
_hasAncestorView(ancestorView: View): boolean;
708713
//@endprivate
709714

710715
/**
@@ -797,7 +802,7 @@ export const isEnabledProperty: Property<View, boolean>;
797802
export const isUserInteractionEnabledProperty: Property<View, boolean>;
798803

799804
export namespace ios {
800-
export function isContentScrollable(controller: any /* UIViewController */, owner: View): boolean
805+
export function isContentScrollable(controller: any /* UIViewController */, owner: View): boolean
801806
export function updateAutoAdjustScrollInsets(controller: any /* UIViewController */, owner: View): void
802807
export function updateConstraints(controller: any /* UIViewController */, owner: View): void;
803808
export function layoutView(controller: any /* UIViewController */, owner: View): void;

0 commit comments

Comments
 (0)