diff --git a/package.json b/package.json index 33ea23ec6..b55814669 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "tslint": "tslint --config build/tslint.json 'tns-core-modules/**/*.ts' 'tests/**/*.ts' 'apps/**/*.ts' 'e2e/**/*.ts' -e '**/node_modules/**' -e '**/platforms/**'", "madge-ios": "tsc --skipLibCheck && tns prepare ios --path tests && madge --circular tests/platforms/ios/tests/app/tns_modules/tns-core-modules", "madge-ios-image": "tsc --skipLibCheck && tns prepare ios --path tests && madge --image graph-tests-ios.svg tests/platforms/ios/tests/app/tns_modules/tns-core-modules", - "madge-android": "tsc --skipLibCheck && tns prepare android --path tests && madge --circular tests/platforms/android/src/main/assets/app/tns_modules/tns-core-modules", - "madge-android-image": "tsc --skipLibCheck && tns prepare android --path tests && madge --image graph-tests-android.svg tests/platforms/android/src/main/assets/app/tns_modules/tns-core-modules" + "madge-android": "tsc --skipLibCheck && tns prepare android --path tests && madge --circular tests/platforms/android/app/src/main/assets/app/tns_modules/tns-core-modules", + "madge-android-image": "tsc --skipLibCheck && tns prepare android --path tests && madge --image graph-tests-android.svg tests/platforms/android/app/src/main/assets/app/tns_modules/tns-core-modules" } } diff --git a/tests/app/ui/frame/frame-tests-common.ts b/tests/app/ui/frame/frame-tests-common.ts index c7f073cf2..7ab48595f 100644 --- a/tests/app/ui/frame/frame-tests-common.ts +++ b/tests/app/ui/frame/frame-tests-common.ts @@ -1,7 +1,8 @@ // >> frame-require -import { topmost, NavigationEntry } from "tns-core-modules/ui/frame"; +import { Frame, getFrameById, topmost, NavigationEntry } from "tns-core-modules/ui/frame"; // << frame-require +import { getRootView } from "tns-core-modules/application"; import { Label } from "tns-core-modules/ui/label"; import { Page } from "tns-core-modules/ui/page"; import * as helper from "../helper"; @@ -223,4 +224,40 @@ export function test_page_parent_when_navigate_back() { }); pages.length = 0; +} + +export function test_frame_retrieval_API_when_navigating() { + const rootView = getRootView(); + + const initialFrame = new Frame(); + initialFrame.id = "initialFrame"; + initialFrame.navigate(() => new Page()); + + const initialTopmost = topmost(); + const initialFrameById = getFrameById("initialFrame"); + + TKUnit.assertEqual(initialTopmost, initialFrame); + TKUnit.assertEqual(initialFrameById, initialFrame); + + const newFrame = new Frame(); + newFrame.id = "newFrame"; + newFrame.navigate(() => new Page()); + + const newTopmost = topmost(); + const newFrameById = getFrameById("newFrame"); + + TKUnit.assertEqual(newTopmost, newFrame); + TKUnit.assertEqual(newFrameById, newFrame); + + initialFrame.navigate(() => new Page()); + + const previousTopmost = topmost(); + const previousFrameById = getFrameById("initialFrame"); + + TKUnit.assertEqual(previousTopmost, initialFrame); + TKUnit.assertEqual(previousFrameById, initialFrame); + + // clean up the frame stack + initialFrame._removeFromFrameStack(); + newFrame._removeFromFrameStack(); } \ No newline at end of file diff --git a/tns-core-modules/ui/frame/frame-common.ts b/tns-core-modules/ui/frame/frame-common.ts index ec9aa493a..810fa8782 100644 --- a/tns-core-modules/ui/frame/frame-common.ts +++ b/tns-core-modules/ui/frame/frame-common.ts @@ -403,10 +403,15 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition { } public _pushInFrameStack() { - if (this._isInFrameStack) { + if (this._isInFrameStack && frameStack[frameStack.length - 1] === this) { return; } + if (this._isInFrameStack) { + const indexOfFrame = frameStack.indexOf(this); + frameStack.splice(indexOfFrame, 1); + } + frameStack.push(this); this._isInFrameStack = true; } @@ -425,7 +430,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition { this._isInFrameStack = false; } - private _removeFromFrameStack() { + public _removeFromFrameStack() { if (!this._isInFrameStack) { return; } @@ -575,6 +580,10 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition { } } +export function getFrameById(id: string): FrameBase { + return frameStack.find((frame) => frame.id && frame.id === id); +} + export function topmost(): FrameBase { if (frameStack.length > 0) { return frameStack[frameStack.length - 1]; diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts index ddfae7881..307fe8a40 100644 --- a/tns-core-modules/ui/frame/frame.android.ts +++ b/tns-core-modules/ui/frame/frame.android.ts @@ -597,7 +597,7 @@ function startActivity(activity: android.app.Activity, frameId: number) { activity.startActivity(intent); } -function getFrameById(frameId: number): Frame { +function getFrameByNumberId(frameId: number): Frame { // Find the frame for this activity. for (let i = 0; i < framesCache.length; i++) { let aliveFrame = framesCache[i].get(); @@ -676,7 +676,7 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { if (!this.entry) { const args = fragment.getArguments(); const frameId = args.getInt(FRAMEID); - const frame = getFrameById(frameId); + const frame = getFrameByNumberId(frameId); if (!frame) { throw new Error(`Cannot find Frame for ${fragment}`); } @@ -999,7 +999,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { if (!rootView) { // If we have frameId from extras - we are starting a new activity from navigation (e.g. new Frame().navigate())) // Then we check if we have frameId from savedInstanceState - this happens when Activity is destroyed but app was not (e.g. suspend) - rootView = getFrameById(frameId) || new Frame(); + rootView = getFrameByNumberId(frameId) || new Frame(); } if (rootView instanceof Frame) { diff --git a/tns-core-modules/ui/frame/frame.d.ts b/tns-core-modules/ui/frame/frame.d.ts index 2ac13eb27..1e3d989b3 100644 --- a/tns-core-modules/ui/frame/frame.d.ts +++ b/tns-core-modules/ui/frame/frame.d.ts @@ -145,6 +145,14 @@ export class Frame extends View { * @private */ _updateBackstack(entry: BackstackEntry, isBack: boolean): void; + /** + * @private + */ + _pushInFrameStack(); + /** + * @private + */ + _removeFromFrameStack(); /** * @private */ @@ -170,6 +178,11 @@ export class Frame extends View { */ export function setFragmentClass(clazz: any): void; +/** + * Gets a frame by id. + */ +export function getFrameById(id: string): Frame; + /** * Gets the topmost frame in the frames stack. An application will typically has one frame instance. Multiple frames handle nested (hierarchical) navigation scenarios. */ @@ -182,6 +195,7 @@ export function topmost(): Frame; export function goBack(); /** + * Deprecated. Use getFrameById() if you want to retrieve a frame different than the topmost one. * Gets the frames stack. */ export function stack(): Array; diff --git a/tns-core-modules/ui/tab-view/tab-view.android.ts b/tns-core-modules/ui/tab-view/tab-view.android.ts index b32654a3e..c4ea595e1 100644 --- a/tns-core-modules/ui/tab-view/tab-view.android.ts +++ b/tns-core-modules/ui/tab-view/tab-view.android.ts @@ -11,6 +11,7 @@ import { import { textTransformProperty, TextTransform, getTransformedText } from "../text-base"; import { fromFileOrResource } from "../../image-source"; import { RESOURCE_PREFIX, ad } from "../../utils/utils"; +import { Frame } from "../frame"; export * from "./tab-view-common"; @@ -473,6 +474,12 @@ export class TabView extends TabViewBase { } }); + const newItem = items[newIndex]; + const selectedView = newItem && newItem.view; + if (selectedView instanceof Frame) { + selectedView._pushInFrameStack(); + } + toLoad.forEach(index => { const item = items[index]; if (this.isLoaded && items[index]) { diff --git a/tns-core-modules/ui/tab-view/tab-view.ios.ts b/tns-core-modules/ui/tab-view/tab-view.ios.ts index 780995593..e5af7b598 100644 --- a/tns-core-modules/ui/tab-view/tab-view.ios.ts +++ b/tns-core-modules/ui/tab-view/tab-view.ios.ts @@ -13,6 +13,7 @@ import { Page } from "../page"; import { profile } from "../../profiling"; import * as uiUtils from "../utils"; import * as utils from "../../utils/utils"; +import { Frame } from "../frame"; export * from "./tab-view-common"; @@ -253,6 +254,11 @@ export class TabView extends TabViewBase { const newItem = items[newIndex]; if (newItem && this.isLoaded) { + const selectedView = items[newIndex].view; + if (selectedView instanceof Frame) { + selectedView._pushInFrameStack(); + } + newItem.loadView(newItem.view); }