Merge pull request #2501 from NativeScript/clear-history-isBackNavigation

FIX: Wrong isBackNavigation value
This commit is contained in:
Alexander Vakrilov
2016-07-25 13:18:03 +03:00
committed by GitHub
3 changed files with 81 additions and 10 deletions

View File

@ -382,4 +382,50 @@ export function test_NavigationEvents_WithBackstackVisibile_False_Forward_Forwar
export function test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward_WithTransition() { export function test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward_WithTransition() {
androidGC(); androidGC();
_test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward({ name: "fade" }); _test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward({ name: "fade" });
}
function _test_NavigationEvents_WithClearHistory(transition?: NavigationTransition) {
const topmost = topmostFrame();
const mainTestPage = topmost.currentPage;
mainTestPage.id = "main-page";
let actualMainPageEvents = new Array<string>();
attachEventListeners(mainTestPage, actualMainPageEvents);
let actualSecondPageEvents = new Array<string>();
const secondPage = new Page();
let secondPageFactory = function (): Page {
secondPage.actionBarHidden = true;
secondPage.id = "second-page";
attachEventListeners(secondPage, actualSecondPageEvents);
secondPage.style.backgroundColor = new Color(255, Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255));
return secondPage;
};
// Go to second page
helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: true, clearHistory: true });
let expectedMainPageEvents = [
"main-page navigatingFrom forward",
"main-page navigatedFrom forward"
];
TKUnit.arrayAssert(actualMainPageEvents, expectedMainPageEvents, "Actual main-page events are different from expected.");
let 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.");
}
export function test_NavigationEvents_WithClearHistory() {
androidGC();
_test_NavigationEvents_WithClearHistory();
}
export function test_NavigationEvents_WithClearHistory_WithTransition() {
androidGC();
_test_NavigationEvents_WithClearHistory({ name: "fade" });
} }

View File

@ -125,6 +125,13 @@ export class Frame extends frameCommon.Frame {
viewController.navigationItem.hidesBackButton = true; viewController.navigationItem.hidesBackButton = true;
let newControllers = NSMutableArray.alloc().initWithCapacity(1); let newControllers = NSMutableArray.alloc().initWithCapacity(1);
newControllers.addObject(viewController); newControllers.addObject(viewController);
// Mark all previous ViewControllers as cleared
const oldControllers = this._ios.controller.viewControllers;
for (let i = 0; i < oldControllers.count; i++) {
oldControllers.objectAtIndex(i).isBackstackCleared = true;
}
this._ios.controller.setViewControllersAnimated(newControllers, animated); this._ios.controller.setViewControllersAnimated(newControllers, animated);
if (trace.enabled) { if (trace.enabled) {
trace.write(`${this}.setViewControllersAnimated([${viewController}], ${animated}); depth = ${navDepth}`, trace.categories.Navigation); trace.write(`${this}.setViewControllersAnimated([${viewController}], ${animated}); depth = ${navDepth}`, trace.categories.Navigation);

View File

@ -7,10 +7,10 @@ import {device} from "platform";
import {DeviceType} from "ui/enums"; import {DeviceType} from "ui/enums";
global.moduleMerge(pageCommon, exports); global.moduleMerge(pageCommon, exports);
var ENTRY = "_entry"; const ENTRY = "_entry";
var DELEGATE = "_delegate"; const DELEGATE = "_delegate";
function isBackNavigation(page: Page, entry): boolean { function isBackNavigationTo(page: Page, entry): boolean {
let frame = page.frame; let frame = page.frame;
if (!frame) { if (!frame) {
return false; return false;
@ -21,7 +21,7 @@ function isBackNavigation(page: Page, entry): boolean {
} }
else { else {
let navigationQueue = (<any>frame)._navigationQueue; let navigationQueue = (<any>frame)._navigationQueue;
for (var i = 0; i < navigationQueue.length; i++) { for (let i = 0; i < navigationQueue.length; i++) {
if (navigationQueue[i].entry === entry) { if (navigationQueue[i].entry === entry) {
return navigationQueue[i].isBackNavigation; return navigationQueue[i].isBackNavigation;
} }
@ -31,11 +31,29 @@ function isBackNavigation(page: Page, entry): boolean {
return false; return false;
} }
function isBackNavigationFrom(controller: UIViewControllerImpl, page: Page): boolean {
if (!page.frame) {
return false;
}
// Controller is cleared or backstack skipped
if (controller.isBackstackCleared || controller.isBackstackSkipped) {
return false;
}
if (controller.navigationController && controller.navigationController.viewControllers.containsObject(controller)) {
return false;
}
return true;
}
class UIViewControllerImpl extends UIViewController { class UIViewControllerImpl extends UIViewController {
private _owner: WeakRef<Page>; private _owner: WeakRef<Page>;
public isBackstackSkipped: boolean; public isBackstackSkipped: boolean;
public isBackstackCleared: boolean;
public static initWithOwner(owner: WeakRef<Page>): UIViewControllerImpl { public static initWithOwner(owner: WeakRef<Page>): UIViewControllerImpl {
let controller = <UIViewControllerImpl>UIViewControllerImpl.new(); let controller = <UIViewControllerImpl>UIViewControllerImpl.new();
@ -130,7 +148,7 @@ class UIViewControllerImpl extends UIViewController {
// Don't raise event if currentPage was showing modal page. // Don't raise event if currentPage was showing modal page.
if (!page._presentedViewController && newEntry && (!frame || frame.currentPage !== page)) { if (!page._presentedViewController && newEntry && (!frame || frame.currentPage !== page)) {
let isBack = isBackNavigation(page, newEntry) let isBack = isBackNavigationTo(page, newEntry);
page.onNavigatingTo(newEntry.entry.context, isBack, newEntry.entry.bindingContext); page.onNavigatingTo(newEntry.entry.context, isBack, newEntry.entry.bindingContext);
} }
@ -179,7 +197,7 @@ class UIViewControllerImpl extends UIViewController {
// Skip navigation events if modal page is shown. // Skip navigation events if modal page is shown.
if (!page._presentedViewController && frame) { if (!page._presentedViewController && frame) {
let newEntry = this[ENTRY]; let newEntry = this[ENTRY];
let isBack = isBackNavigation(page, newEntry); let isBack = isBackNavigationTo(page, newEntry);
// We are on the current page which happens when navigation is canceled so isBack should be false. // We are on the current page which happens when navigation is canceled so isBack should be false.
if (frame.currentPage === page && frame._navigationQueue.length === 0) { if (frame.currentPage === page && frame._navigationQueue.length === 0) {
isBack = false; isBack = false;
@ -224,10 +242,10 @@ class UIViewControllerImpl extends UIViewController {
page._presentedViewController = this.presentedViewController; page._presentedViewController = this.presentedViewController;
} }
var frame = page.frame; const frame = page.frame;
// Skip navigation events if we are hiding because we are about to show modal page. // Skip navigation events if we are hiding because we are about to show modal page.
if (!page._presentedViewController && frame && frame.currentPage === page) { if (!page._presentedViewController && frame && frame.currentPage === page) {
let isBack = page.frame && (!this.navigationController || !this.navigationController.viewControllers.containsObject(this)) && !this.isBackstackSkipped; let isBack = isBackNavigationFrom(this, page);
page.onNavigatingFrom(isBack); page.onNavigatingFrom(isBack);
} }
@ -267,7 +285,7 @@ class UIViewControllerImpl extends UIViewController {
// Remove from parent if page was in frame and we navigated back. // Remove from parent if page was in frame and we navigated back.
// Showing page modally will not pass isBack check so currentPage won't be removed from Frame. // Showing page modally will not pass isBack check so currentPage won't be removed from Frame.
let isBack = frame && (!this.navigationController || !this.navigationController.viewControllers.containsObject(this)) && !this.isBackstackSkipped; let isBack = isBackNavigationFrom(this, page);
if (isBack) { if (isBack) {
// Remove parent when navigating back. // Remove parent when navigating back.
frame._removeView(page); frame._removeView(page);
@ -398,7 +416,7 @@ export class Page extends pageCommon.Page {
} }
public _updateActionBar(hidden: boolean) { public _updateActionBar(hidden: boolean) {
var frame = this.frame; const frame = this.frame;
if (frame) { if (frame) {
frame._updateActionBar(this); frame._updateActionBar(this);
} }