mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 11:42:04 +08:00
feat(frame): hardware back in parent frame when back states available (#6446)
This commit is contained in:

committed by
Martin Yankov

parent
9f7df1868c
commit
af651d6e83
@ -1,9 +1,11 @@
|
||||
import * as TKUnit from "../TKUnit";
|
||||
import { EventData, Page, NavigatedData } from "tns-core-modules/ui/page";
|
||||
import { topmost as topmostFrame, NavigationTransition } from "tns-core-modules/ui/frame";
|
||||
import { StackLayout, } from "tns-core-modules/ui/layouts/stack-layout";
|
||||
import { GridLayout, } from "tns-core-modules/ui/layouts/grid-layout";
|
||||
import { Color } from "tns-core-modules/color";
|
||||
import * as helper from "../ui/helper";
|
||||
|
||||
import * as frame from "tns-core-modules/ui/frame";
|
||||
// Creates a random colorful page full of meaningless stuff.
|
||||
let id = 0;
|
||||
let pageFactory = function (): Page {
|
||||
@ -51,6 +53,65 @@ export function test_backstackVisible_WithTransition() {
|
||||
_test_backstackVisible({ name: "fade", duration: 10 });
|
||||
}
|
||||
|
||||
export function test_backAndForwardParentPage_nestedFrames() {
|
||||
const topmost = topmostFrame();
|
||||
const mainTestPage = topmost.currentPage;
|
||||
let innerFrame;
|
||||
|
||||
const page = (title) => {
|
||||
const p = new Page();
|
||||
p["tag"] = title;
|
||||
return p;
|
||||
};
|
||||
|
||||
const parentPage = (title, innerPage) => {
|
||||
const parentPage = new Page();
|
||||
parentPage["tag"] = title;
|
||||
|
||||
const stack = new StackLayout();
|
||||
innerFrame = new frame.Frame();
|
||||
innerFrame.navigate({ create: () => innerPage });
|
||||
stack.addChild(innerFrame);
|
||||
parentPage.content = stack;
|
||||
|
||||
return parentPage;
|
||||
}
|
||||
|
||||
const back = pages => topmostFrame().goBack(topmostFrame().backStack[topmostFrame().backStack.length - pages]);
|
||||
const currentPageMustBe = tag => TKUnit.assertEqual(topmostFrame().currentPage["tag"], tag, "Expected current page to be " + tag + " it was " + topmostFrame().currentPage["tag"] + " instead.");
|
||||
|
||||
let parentPage1, parentPage2, innerPage1, innerPage2;
|
||||
innerPage1 = page("InnerPage1");
|
||||
innerPage2 = page("InnerPage2");
|
||||
parentPage1 = page("ParentPage1");
|
||||
parentPage2 = parentPage("ParentPage2", innerPage1);
|
||||
|
||||
helper.waitUntilNavigatedTo(parentPage1, () => topmost.navigate({ create: () => parentPage1 }));
|
||||
currentPageMustBe("ParentPage1");
|
||||
|
||||
helper.waitUntilNavigatedTo(parentPage2, () => topmost.navigate({ create: () => parentPage2 }));
|
||||
currentPageMustBe("ParentPage2");
|
||||
|
||||
helper.waitUntilNavigatedTo(innerPage2, () => innerFrame.navigate({ create: () => innerPage2 }));
|
||||
currentPageMustBe("InnerPage2");
|
||||
|
||||
helper.waitUntilNavigatedTo(innerPage1, () => frame.goBack());
|
||||
currentPageMustBe("InnerPage1");
|
||||
|
||||
helper.waitUntilNavigatedTo(parentPage1, () => frame.goBack());
|
||||
currentPageMustBe("ParentPage1");
|
||||
|
||||
helper.waitUntilNavigatedTo(parentPage2, () => topmost.navigate({ create: () => parentPage2 }));
|
||||
currentPageMustBe("ParentPage2");
|
||||
|
||||
back(2);
|
||||
TKUnit.waitUntilReady(() => topmostFrame().navigationQueueIsEmpty());
|
||||
|
||||
const frameStack = frame.stack();
|
||||
TKUnit.assertEqual(frameStack.length, 1, "There should be only one frame left in the stack");
|
||||
TKUnit.assertEqual(topmostFrame().currentPage, mainTestPage, "We should be on the main test page at the end of the test.");
|
||||
}
|
||||
|
||||
function _test_backToEntry(transition?: NavigationTransition) {
|
||||
const topmost = topmostFrame();
|
||||
const page = (tag) => () => {
|
||||
@ -362,10 +423,10 @@ function _test_NavigationEvents_WithClearHistory(transition?: NavigationTransiti
|
||||
// Go to second page
|
||||
helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: !!transition, clearHistory: true });
|
||||
|
||||
const expectedMainPageEvents = [ "main-page navigatingFrom forward", "main-page navigatedFrom forward" ];
|
||||
const expectedMainPageEvents = ["main-page navigatingFrom forward", "main-page navigatedFrom forward"];
|
||||
TKUnit.arrayAssert(actualMainPageEvents, expectedMainPageEvents, "Actual main-page events are different from expected.");
|
||||
|
||||
const expectedSecondPageEvents = [ "second-page navigatingTo forward", "second-page navigatedTo forward" ];
|
||||
const expectedSecondPageEvents = ["second-page navigatingTo forward", "second-page navigatedTo forward"];
|
||||
TKUnit.arrayAssert(actualSecondPageEvents, expectedSecondPageEvents, "Actual main-page events are different from expected.");
|
||||
|
||||
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) {
|
||||
const firstPageFactory = function (): Page {
|
||||
const firstPage = new Page();
|
||||
firstPage.id = "first-page";
|
||||
firstPage.on(eventName, (args: EventData) => {
|
||||
firstPage.on(eventName, (args: EventData) => {
|
||||
const page = <Page>args.object;
|
||||
const frame = page.frame;
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { Frame as FrameDefinition, NavigationEntry, BackstackEntry, NavigationTr
|
||||
import { Page } from "../page";
|
||||
|
||||
// Types.
|
||||
import { getAncestor } from "../core/view/view-common";
|
||||
import { View, CustomLayoutView, isIOS, isAndroid, traceEnabled, traceWrite, traceCategories, Property, CSSType } from "../core/view";
|
||||
import { createViewFromEntry } from "../builder";
|
||||
import { profile } from "../../profiling";
|
||||
@ -215,6 +216,10 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
|
||||
this._currentEntry = entry;
|
||||
|
||||
if (isBack) {
|
||||
this._pushInFrameStack();
|
||||
}
|
||||
|
||||
newPage.onNavigatedTo(isBack);
|
||||
|
||||
// Reset executing entry after NavigatedTo is raised;
|
||||
@ -573,6 +578,22 @@ export function goBack(): boolean {
|
||||
if (top && top.canGoBack()) {
|
||||
top.goBack();
|
||||
return true;
|
||||
} else if (top) {
|
||||
let parentFrameCanGoBack = false;
|
||||
let parentFrame = <FrameBase>getAncestor(top, "Frame");
|
||||
|
||||
while (parentFrame && !parentFrameCanGoBack) {
|
||||
if (parentFrame && parentFrame.canGoBack()) {
|
||||
parentFrameCanGoBack = true;
|
||||
} else {
|
||||
parentFrame = <FrameBase>getAncestor(top, "Frame");
|
||||
}
|
||||
}
|
||||
|
||||
if (parentFrame && parentFrameCanGoBack) {
|
||||
parentFrame.goBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (frameStack.length > 1) {
|
||||
|
@ -204,8 +204,8 @@ export class Frame extends FrameBase {
|
||||
// however, we must add a fragment.isAdded() guard as our logic will try to
|
||||
// explicitly remove the already removed child fragment causing an
|
||||
// IllegalStateException: Fragment has not been attached yet.
|
||||
if (!this._currentEntry ||
|
||||
!this._currentEntry.fragment ||
|
||||
if (!this._currentEntry ||
|
||||
!this._currentEntry.fragment ||
|
||||
!this._currentEntry.fragment.isAdded()) {
|
||||
return;
|
||||
}
|
||||
@ -423,6 +423,7 @@ export class Frame extends FrameBase {
|
||||
}
|
||||
|
||||
this._android.rootViewGroup = null;
|
||||
this._removeFromFrameStack();
|
||||
super.disposeNativeView();
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,11 @@ export class Frame extends FrameBase {
|
||||
return this.viewController.view;
|
||||
}
|
||||
|
||||
public disposeNativeView() {
|
||||
this._removeFromFrameStack();
|
||||
super.disposeNativeView();
|
||||
}
|
||||
|
||||
public get ios(): iOSFrame {
|
||||
return this._ios;
|
||||
}
|
||||
|
Reference in New Issue
Block a user