Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit af651d6

Browse files
ADjenkovMartoYankov
authored andcommitted
feat(frame): hardware back in parent frame when back states available (NativeScript#6446)
1 parent 9f7df18 commit af651d6

File tree

4 files changed

+94
-6
lines changed

4 files changed

+94
-6
lines changed

tests/app/navigation/navigation-tests.ts

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as TKUnit from "../TKUnit";
22
import { EventData, Page, NavigatedData } from "tns-core-modules/ui/page";
33
import { topmost as topmostFrame, NavigationTransition } from "tns-core-modules/ui/frame";
4+
import { StackLayout, } from "tns-core-modules/ui/layouts/stack-layout";
5+
import { GridLayout, } from "tns-core-modules/ui/layouts/grid-layout";
46
import { Color } from "tns-core-modules/color";
57
import * as helper from "../ui/helper";
6-
8+
import * as frame from "tns-core-modules/ui/frame";
79
// Creates a random colorful page full of meaningless stuff.
810
let id = 0;
911
let pageFactory = function (): Page {
@@ -51,6 +53,65 @@ export function test_backstackVisible_WithTransition() {
5153
_test_backstackVisible({ name: "fade", duration: 10 });
5254
}
5355

56+
export function test_backAndForwardParentPage_nestedFrames() {
57+
const topmost = topmostFrame();
58+
const mainTestPage = topmost.currentPage;
59+
let innerFrame;
60+
61+
const page = (title) => {
62+
const p = new Page();
63+
p["tag"] = title;
64+
return p;
65+
};
66+
67+
const parentPage = (title, innerPage) => {
68+
const parentPage = new Page();
69+
parentPage["tag"] = title;
70+
71+
const stack = new StackLayout();
72+
innerFrame = new frame.Frame();
73+
innerFrame.navigate({ create: () => innerPage });
74+
stack.addChild(innerFrame);
75+
parentPage.content = stack;
76+
77+
return parentPage;
78+
}
79+
80+
const back = pages => topmostFrame().goBack(topmostFrame().backStack[topmostFrame().backStack.length - pages]);
81+
const currentPageMustBe = tag => TKUnit.assertEqual(topmostFrame().currentPage["tag"], tag, "Expected current page to be " + tag + " it was " + topmostFrame().currentPage["tag"] + " instead.");
82+
83+
let parentPage1, parentPage2, innerPage1, innerPage2;
84+
innerPage1 = page("InnerPage1");
85+
innerPage2 = page("InnerPage2");
86+
parentPage1 = page("ParentPage1");
87+
parentPage2 = parentPage("ParentPage2", innerPage1);
88+
89+
helper.waitUntilNavigatedTo(parentPage1, () => topmost.navigate({ create: () => parentPage1 }));
90+
currentPageMustBe("ParentPage1");
91+
92+
helper.waitUntilNavigatedTo(parentPage2, () => topmost.navigate({ create: () => parentPage2 }));
93+
currentPageMustBe("ParentPage2");
94+
95+
helper.waitUntilNavigatedTo(innerPage2, () => innerFrame.navigate({ create: () => innerPage2 }));
96+
currentPageMustBe("InnerPage2");
97+
98+
helper.waitUntilNavigatedTo(innerPage1, () => frame.goBack());
99+
currentPageMustBe("InnerPage1");
100+
101+
helper.waitUntilNavigatedTo(parentPage1, () => frame.goBack());
102+
currentPageMustBe("ParentPage1");
103+
104+
helper.waitUntilNavigatedTo(parentPage2, () => topmost.navigate({ create: () => parentPage2 }));
105+
currentPageMustBe("ParentPage2");
106+
107+
back(2);
108+
TKUnit.waitUntilReady(() => topmostFrame().navigationQueueIsEmpty());
109+
110+
const frameStack = frame.stack();
111+
TKUnit.assertEqual(frameStack.length, 1, "There should be only one frame left in the stack");
112+
TKUnit.assertEqual(topmostFrame().currentPage, mainTestPage, "We should be on the main test page at the end of the test.");
113+
}
114+
54115
function _test_backToEntry(transition?: NavigationTransition) {
55116
const topmost = topmostFrame();
56117
const page = (tag) => () => {
@@ -362,10 +423,10 @@ function _test_NavigationEvents_WithClearHistory(transition?: NavigationTransiti
362423
// Go to second page
363424
helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: !!transition, clearHistory: true });
364425

365-
const expectedMainPageEvents = [ "main-page navigatingFrom forward", "main-page navigatedFrom forward" ];
426+
const expectedMainPageEvents = ["main-page navigatingFrom forward", "main-page navigatedFrom forward"];
366427
TKUnit.arrayAssert(actualMainPageEvents, expectedMainPageEvents, "Actual main-page events are different from expected.");
367428

368-
const expectedSecondPageEvents = [ "second-page navigatingTo forward", "second-page navigatedTo forward" ];
429+
const expectedSecondPageEvents = ["second-page navigatingTo forward", "second-page navigatedTo forward"];
369430
TKUnit.arrayAssert(actualSecondPageEvents, expectedSecondPageEvents, "Actual main-page events are different from expected.");
370431

371432
TKUnit.assertEqual(topmost.currentPage, secondPage, "We should be on the second page at the end of the test.");
@@ -393,7 +454,7 @@ function _test_Navigate_From_Page_Event_Handler(eventName: string) {
393454
const firstPageFactory = function (): Page {
394455
const firstPage = new Page();
395456
firstPage.id = "first-page";
396-
firstPage.on(eventName, (args: EventData) => {
457+
firstPage.on(eventName, (args: EventData) => {
397458
const page = <Page>args.object;
398459
const frame = page.frame;
399460

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Frame as FrameDefinition, NavigationEntry, BackstackEntry, NavigationTr
33
import { Page } from "../page";
44

55
// Types.
6+
import { getAncestor } from "../core/view/view-common";
67
import { View, CustomLayoutView, isIOS, isAndroid, traceEnabled, traceWrite, traceCategories, Property, CSSType } from "../core/view";
78
import { createViewFromEntry } from "../builder";
89
import { profile } from "../../profiling";
@@ -215,6 +216,10 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
215216

216217
this._currentEntry = entry;
217218

219+
if (isBack) {
220+
this._pushInFrameStack();
221+
}
222+
218223
newPage.onNavigatedTo(isBack);
219224

220225
// Reset executing entry after NavigatedTo is raised;
@@ -573,6 +578,22 @@ export function goBack(): boolean {
573578
if (top && top.canGoBack()) {
574579
top.goBack();
575580
return true;
581+
} else if (top) {
582+
let parentFrameCanGoBack = false;
583+
let parentFrame = <FrameBase>getAncestor(top, "Frame");
584+
585+
while (parentFrame && !parentFrameCanGoBack) {
586+
if (parentFrame && parentFrame.canGoBack()) {
587+
parentFrameCanGoBack = true;
588+
} else {
589+
parentFrame = <FrameBase>getAncestor(top, "Frame");
590+
}
591+
}
592+
593+
if (parentFrame && parentFrameCanGoBack) {
594+
parentFrame.goBack();
595+
return true;
596+
}
576597
}
577598

578599
if (frameStack.length > 1) {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ export class Frame extends FrameBase {
204204
// however, we must add a fragment.isAdded() guard as our logic will try to
205205
// explicitly remove the already removed child fragment causing an
206206
// IllegalStateException: Fragment has not been attached yet.
207-
if (!this._currentEntry ||
208-
!this._currentEntry.fragment ||
207+
if (!this._currentEntry ||
208+
!this._currentEntry.fragment ||
209209
!this._currentEntry.fragment.isAdded()) {
210210
return;
211211
}
@@ -423,6 +423,7 @@ export class Frame extends FrameBase {
423423
}
424424

425425
this._android.rootViewGroup = null;
426+
this._removeFromFrameStack();
426427
super.disposeNativeView();
427428
}
428429

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ export class Frame extends FrameBase {
3636
return this.viewController.view;
3737
}
3838

39+
public disposeNativeView() {
40+
this._removeFromFrameStack();
41+
super.disposeNativeView();
42+
}
43+
3944
public get ios(): iOSFrame {
4045
return this._ios;
4146
}

0 commit comments

Comments
 (0)