Skip to content

Commit 27622d8

Browse files
authored
fix-next: ensure proper events on tab change (NativeScript#5468)
1 parent 949a99e commit 27622d8

File tree

7 files changed

+141
-25
lines changed

7 files changed

+141
-25
lines changed

tests/app/navigation/reset-root-view-tests.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as TKUnit from "../TKUnit";
2+
import * as helper from "../ui/helper";
23
import { Page } from "tns-core-modules/ui/page";
34
import { Frame, NavigationEntry, stack } from "tns-core-modules/ui/frame";
45
import { _resetRootView, getRootView } from "tns-core-modules/application";
@@ -47,8 +48,7 @@ function createTestTabRootEntry() {
4748
export function test_reset_frame_to_frame() {
4849
const testFrameRoot1 = createTestFrameRootEntry();
4950

50-
_resetRootView(testFrameRoot1.entry);
51-
TKUnit.waitUntilReady(() => testFrameRoot1.page.isLoaded);
51+
helper.waitUntilNavigatedTo(testFrameRoot1.page, () => _resetRootView(testFrameRoot1.entry));
5252

5353
const rootView1 = getRootView();
5454
const frameStack1 = stack();
@@ -57,8 +57,7 @@ export function test_reset_frame_to_frame() {
5757

5858
const testFrameRoot2 = createTestFrameRootEntry();
5959

60-
_resetRootView(testFrameRoot2.entry);
61-
TKUnit.waitUntilReady(() => testFrameRoot2.page.isLoaded);
60+
helper.waitUntilNavigatedTo(testFrameRoot2.page, () => _resetRootView(testFrameRoot2.entry));
6261

6362
const rootView2 = getRootView();
6463
const frameStack2 = stack();
@@ -69,8 +68,7 @@ export function test_reset_frame_to_frame() {
6968
export function test_reset_frame_to_tab() {
7069
const testFrameRoot = createTestFrameRootEntry();
7170

72-
_resetRootView(testFrameRoot.entry);
73-
TKUnit.waitUntilReady(() => testFrameRoot.page.isLoaded);
71+
helper.waitUntilNavigatedTo(testFrameRoot.page, () => _resetRootView(testFrameRoot.entry));
7472

7573
const rootView1 = getRootView();
7674
const frameStack1 = stack();
@@ -79,8 +77,7 @@ export function test_reset_frame_to_tab() {
7977

8078
const testTabRoot = createTestTabRootEntry();
8179

82-
_resetRootView(testTabRoot.entry);
83-
TKUnit.waitUntilReady(() => testTabRoot.page.isLoaded);
80+
helper.waitUntilNavigatedTo(testTabRoot.page, () => _resetRootView(testTabRoot.entry));
8481

8582
const rootView2 = getRootView();
8683
const frameStack2 = stack();
@@ -91,8 +88,7 @@ export function test_reset_frame_to_tab() {
9188
export function test_reset_tab_to_frame() {
9289
const testTabRoot = createTestTabRootEntry();
9390

94-
_resetRootView(testTabRoot.entry);
95-
TKUnit.waitUntilReady(() => testTabRoot.page.isLoaded);
91+
helper.waitUntilNavigatedTo(testTabRoot.page, () => _resetRootView(testTabRoot.entry));
9692

9793
const rootView2 = getRootView();
9894
const frameStack2 = stack();
@@ -101,8 +97,7 @@ export function test_reset_tab_to_frame() {
10197

10298
const testFrameRoot = createTestFrameRootEntry();
10399

104-
_resetRootView(testFrameRoot.entry);
105-
TKUnit.waitUntilReady(() => testFrameRoot.page.isLoaded);
100+
helper.waitUntilNavigatedTo(testFrameRoot.page, () => _resetRootView(testFrameRoot.entry));
106101

107102
const rootView1 = getRootView();
108103
const frameStack1 = stack();
@@ -113,8 +108,7 @@ export function test_reset_tab_to_frame() {
113108
export function test_reset_tab_to_tab() {
114109
const testTabRoot1 = createTestTabRootEntry();
115110

116-
_resetRootView(testTabRoot1.entry);
117-
TKUnit.waitUntilReady(() => testTabRoot1.page.isLoaded);
111+
helper.waitUntilNavigatedTo(testTabRoot1.page, () => _resetRootView(testTabRoot1.entry));
118112

119113
const rootView1 = getRootView();
120114
const frameStack1 = stack();
@@ -123,15 +117,28 @@ export function test_reset_tab_to_tab() {
123117

124118
const testTabRoot2 = createTestTabRootEntry();
125119

126-
_resetRootView(testTabRoot2.entry);
127-
TKUnit.waitUntilReady(() => testTabRoot2.page.isLoaded);
120+
helper.waitUntilNavigatedTo(testTabRoot2.page, () => _resetRootView(testTabRoot2.entry));
128121

129122
const rootView2 = getRootView();
130123
const frameStack2 = stack();
131124
TKUnit.assertEqual(rootView2, testTabRoot2.root);
132125
TKUnit.assertEqual(frameStack2.length, 2);
133126
};
134127

128+
export function test_reset_during_tab_index_change() {
129+
const testTabRoot = createTestTabRootEntry();
130+
131+
helper.waitUntilNavigatedTo(testTabRoot.page, () => _resetRootView(testTabRoot.entry));
132+
133+
testTabRoot.root.selectedIndex = 1;
134+
135+
const testFrameRoot = createTestFrameRootEntry();
136+
137+
helper.waitUntilNavigatedTo(testFrameRoot.page, () => _resetRootView(testFrameRoot.entry));
138+
139+
TKUnit.assertTrue(true);
140+
}
141+
135142
export function tearDownModule() {
136143
// reset the root to frame for other tests
137144
const resetFrameRoot = createTestFrameRootEntry();

tests/app/testRunner.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ allTests["TAB-VIEW"] = tabViewTests;
165165
import * as tabViewNavigationTests from "./ui/tab-view/tab-view-navigation-tests";
166166
allTests["TAB-VIEW-NAVIGATION"] = tabViewNavigationTests;
167167

168+
import * as tabViewRootTests from "./ui/tab-view/tab-view-root-tests";
169+
allTests["TAB-VIEW-ROOT"] = tabViewRootTests;
170+
168171
import * as imageTests from "./ui/image/image-tests";
169172
allTests["IMAGE"] = imageTests;
170173

tests/app/ui/helper.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,18 @@ export function getClearCurrentPage(): Page {
154154
return page;
155155
}
156156

157+
export function waitUntilNavigatedTo(page: Page, action: Function) {
158+
let completed = false;
159+
function navigatedTo(args) {
160+
args.object.page.off("navigatedTo", navigatedTo);
161+
completed = true;
162+
}
163+
164+
page.on("navigatedTo", navigatedTo);
165+
action();
166+
TKUnit.waitUntilReady(() => completed, 100);
167+
}
168+
157169
export function waitUntilNavigatedFrom(action: Function) {
158170
const currentPage = frame.topmost().currentPage;
159171
let completed = false;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import * as helper from "../helper";
2+
import TKUnit = require("../../TKUnit");
3+
import { _resetRootView } from "tns-core-modules/application/";
4+
import { Frame, NavigationEntry } from "tns-core-modules/ui/frame";
5+
import { Page } from "tns-core-modules/ui/page";
6+
import { TabView, TabViewItem } from "tns-core-modules/ui/tab-view";
7+
8+
export function test_whenChangingTabsWithFramesCorrectEventsAreRaised() {
9+
const actualEventsRaised = [];
10+
11+
function attachPageEventHandlers(page: Page) {
12+
page.on(Page.loadedEvent, () => actualEventsRaised.push(`${page.id} loaded`));
13+
page.on(Page.unloadedEvent, () => actualEventsRaised.push(`${page.id} unloaded`));
14+
page.on(Page.navigatingToEvent, () => actualEventsRaised.push(`${page.id} navigatingTo`));
15+
page.on(Page.navigatingFromEvent, () => actualEventsRaised.push(`${page.id} navigatingFrom`));
16+
page.on(Page.navigatedToEvent, () => actualEventsRaised.push(`${page.id} navigatedTo`));
17+
page.on(Page.navigatedFromEvent, () => actualEventsRaised.push(`${page.id} navigatedFrom`));
18+
}
19+
20+
function attachFrameEventHandlers(frame: Frame) {
21+
frame.on(Frame.loadedEvent, () => actualEventsRaised.push(`${frame.id} loaded`));
22+
frame.on(Frame.unloadedEvent, () => actualEventsRaised.push(`${frame.id} unloaded`));
23+
}
24+
25+
const page1 = new Page();
26+
page1.id = "Tab1 Frame1 Page1";
27+
attachPageEventHandlers(page1);
28+
29+
const frame1 = new Frame();
30+
frame1.navigate(() => page1);
31+
frame1.id = "Tab1 Frame1";
32+
attachFrameEventHandlers(frame1);
33+
34+
const page2 = new Page();
35+
page2.id = "Tab2 Frame2 Page2";
36+
attachPageEventHandlers(page2);
37+
38+
const frame2 = new Frame();
39+
frame2.navigate(() => page2);
40+
frame2.id = "Tab2 Frame2";
41+
attachFrameEventHandlers(frame2);
42+
43+
const tabView = new TabView();
44+
const tabEntry1 = new TabViewItem();
45+
tabEntry1.title = "frame1";
46+
tabEntry1.view = frame1;
47+
const tabEntry2 = new TabViewItem();
48+
tabEntry2.title = "frame2";
49+
tabEntry2.view = frame2;
50+
tabView.items = [tabEntry1, tabEntry2];
51+
52+
const entry: NavigationEntry = {
53+
create: () => tabView
54+
};
55+
56+
helper.waitUntilNavigatedTo(page1, () => _resetRootView(entry));
57+
helper.waitUntilNavigatedTo(page2, () => tabView.selectedIndex = 1);
58+
tabView.selectedIndex = 0;
59+
TKUnit.waitUntilReady(() => page1.isLoaded);
60+
61+
const expectedEventsRaised = [
62+
"Tab1 Frame1 loaded",
63+
"Tab1 Frame1 Page1 navigatingTo",
64+
"Tab1 Frame1 Page1 loaded",
65+
"Tab1 Frame1 Page1 navigatedTo",
66+
"Tab1 Frame1 Page1 unloaded",
67+
"Tab1 Frame1 unloaded",
68+
"Tab2 Frame2 loaded",
69+
"Tab2 Frame2 Page2 navigatingTo",
70+
"Tab2 Frame2 Page2 loaded",
71+
"Tab2 Frame2 Page2 navigatedTo",
72+
"Tab2 Frame2 Page2 unloaded",
73+
"Tab2 Frame2 unloaded",
74+
"Tab1 Frame1 Page1 loaded",
75+
"Tab1 Frame1 loaded"
76+
];
77+
78+
TKUnit.arrayAssert(actualEventsRaised, expectedEventsRaised);
79+
}
80+
81+
export function tearDownModule() {
82+
const page = new Page();
83+
const frame = new Frame();
84+
frame.navigate(() => page);
85+
86+
const entry: NavigationEntry = {
87+
create: () => frame
88+
};
89+
90+
helper.waitUntilNavigatedTo(page, () => _resetRootView(entry));
91+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,7 @@ export class Frame extends FrameBase {
201201
const currentEntryChanged = current !== entry;
202202
if (currentEntryChanged) {
203203
this._updateBackstack(entry, isBack);
204-
}
205204

206-
if (currentEntryChanged) {
207205
// If activity was destroyed we need to destroy fragment and UI
208206
// of current and new entries.
209207
if (this._tearDownPending) {
@@ -936,7 +934,9 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
936934

937935
public resetActivityContent(activity: android.app.Activity): void {
938936
if (this._rootView) {
939-
// if we already have a root view, we reset it.
937+
const manager = this._rootView._getFragmentManager();
938+
manager.executePendingTransactions();
939+
940940
this._rootView._onRootViewReset();
941941
}
942942
// Delete previously cached root view in order to recreate it.

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ export class Frame extends FrameBase {
3838
}
3939

4040
public setCurrent(entry: BackstackEntry, isBack: boolean): void {
41-
if (entry !== this._currentEntry) {
41+
const current = this._currentEntry;
42+
const currentEntryChanged = current !== entry;
43+
if (currentEntryChanged) {
4244
this._updateBackstack(entry, isBack);
43-
}
4445

45-
super.setCurrent(entry, isBack);
46+
super.setCurrent(entry, isBack);
47+
}
4648
}
4749

4850
@profile

tns-core-modules/ui/tab-view/tab-view.ios.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class UITabBarControllerImpl extends UITabBarController {
3232
public viewWillAppear(animated: boolean): void {
3333
super.viewWillAppear(animated);
3434
const owner = this._owner.get();
35-
if(!owner){
35+
if (!owner) {
3636
return;
3737
}
3838

@@ -147,7 +147,7 @@ function updateItemIconPosition(tabBarItem: UITabBarItem): void {
147147

148148
export class TabViewItem extends TabViewItemBase {
149149
private __controller: UIViewController;
150-
150+
151151
public setViewController(controller: UIViewController, nativeView: UIView) {
152152
this.__controller = controller;
153153
this.setNativeView(nativeView);
@@ -295,7 +295,7 @@ export class TabView extends TabViewBase {
295295

296296
private getViewController(item: TabViewItem): UIViewController {
297297
let newController: UIViewController = item.view ? item.view.viewController : null;
298-
298+
299299
if (newController) {
300300
item.setViewController(newController, newController.view);
301301
return newController;
@@ -399,6 +399,7 @@ export class TabView extends TabViewBase {
399399
}
400400

401401
if (value > -1) {
402+
(<any>this._ios)._willSelectViewController = this._ios.viewControllers[value];
402403
this._ios.selectedIndex = value;
403404
}
404405
}

0 commit comments

Comments
 (0)