Merge pull request #1838 from NativeScript/feature/modal-dialog-imprvements

ShownModally fired when the dialog is actually shown in Android
This commit is contained in:
Alexander Vakrilov
2016-03-24 18:01:58 +02:00
6 changed files with 126 additions and 103 deletions

View File

@ -28,6 +28,9 @@ import stackLayoutModule = require("ui/layouts/stack-layout");
import helper = require("../helper"); import helper = require("../helper");
import view = require("ui/core/view"); import view = require("ui/core/view");
import observable = require("data/observable"); import observable = require("data/observable");
import {Page, ShownModallyData} from "ui/page";
import {Label} from "ui/label";
import {EventData} from "data/observable";
export function addLabelToPage(page: PageModule.Page, text?: string) { export function addLabelToPage(page: PageModule.Page, text?: string) {
var label = new LabelModule.Label(); var label = new LabelModule.Label();
@ -440,6 +443,76 @@ export function test_WhenNavigatingForwardAndBack_IsBackNavigationIsCorrect() {
helper.goBack(); helper.goBack();
} }
export function test_WhenPageIsNavigatedToItCanShowAnotherPageAsModal() {
var masterPage;
var ctx = {
shownModally: false
};
var modalClosed = false;
var modalCloseCallback = function (returnValue: any) {
TKUnit.assertTrue(ctx.shownModally, "Modal-page must be shown!");
TKUnit.assertEqual(returnValue, "return value", "Modal-page must return value!");
modalClosed = true;
}
let modalPage: Page;
let shownModally = 0;
var onShownModal = function (args: ShownModallyData) {
shownModally++;
modalPage.off(Page.shownModallyEvent, onShownModal);
}
let modalLoaded = 0;
var onModalLoaded = function (args: EventData) {
modalLoaded++;
modalPage.off(Page.loadedEvent, onModalLoaded);
}
let modalUnloaded = 0;
var onModalUnloaded = function (args: EventData) {
modalUnloaded++;
modalPage.off(Page.unloadedEvent, onModalUnloaded);
TKUnit.assertNull(masterPage.modal, "currentPage.modal should be undefined when no modal page is shown!");
}
var navigatedToEventHandler = function (args) {
let page = <Page>args.object;
TKUnit.assertNull(page.modal, "currentPage.modal should be undefined when no modal page is shown!");
let basePath = "ui/page/";
modalPage = page.showModal(basePath + "modal-page", ctx, modalCloseCallback, false);
TKUnit.assertTrue((<any>modalPage).showingModally, "showingModally");
modalPage.on(Page.shownModallyEvent, onShownModal);
modalPage.on(Page.loadedEvent, onModalLoaded);
modalPage.on(Page.unloadedEvent, onModalUnloaded);
};
var masterPageFactory = function (): Page {
masterPage = new Page();
masterPage.id = "newPage";
masterPage.on(Page.navigatedToEvent, navigatedToEventHandler);
var label = new Label();
label.text = "Text";
masterPage.content = label;
return masterPage;
};
try {
helper.navigate(masterPageFactory);
TKUnit.waitUntilReady(() => { return modalUnloaded > 0; });
TKUnit.assertEqual(shownModally, 1, "shownModally");
TKUnit.assertEqual(modalLoaded, 1, "modalLoaded");
TKUnit.assertEqual(modalUnloaded, 1, "modalUnloaded");
masterPage.off(Page.navigatedToEvent, navigatedToEventHandler);
}
finally {
helper.goBack();
}
}
//export function test_ModalPage_Layout_is_Correct() { //export function test_ModalPage_Layout_is_Correct() {
// var testPage: PageModule.Page; // var testPage: PageModule.Page;
// var label: LabelModule.Label; // var label: LabelModule.Label;

View File

@ -1,5 +1,5 @@
import PageTestCommon = require("./page-tests-common"); import PageTestCommon = require("./page-tests-common");
import {Page, ShownModallyData} from "ui/page"; import {Page} from "ui/page";
import TKUnit = require("../../TKUnit"); import TKUnit = require("../../TKUnit");
import {Label} from "ui/label"; import {Label} from "ui/label";
import helper = require("../helper"); import helper = require("../helper");
@ -27,76 +27,6 @@ export function test_NavigateToNewPage_InnerControl() {
TKUnit.assertFalse(label.isLoaded, "label.isLoaded should become false after navigating back"); TKUnit.assertFalse(label.isLoaded, "label.isLoaded should become false after navigating back");
} }
export function test_WhenPageIsNavigatedToItCanShowAnotherPageAsModal() {
var masterPage;
var ctx = {
shownModally: false
};
var modalClosed = false;
var modalCloseCallback = function (returnValue: any) {
TKUnit.assertTrue(ctx.shownModally, "Modal-page must be shown!");
TKUnit.assertEqual(returnValue, "return value", "Modal-page must return value!");
modalClosed = true;
}
let modalPage: Page;
let shownModally = 0;
var onShownModal = function (args: ShownModallyData) {
shownModally++;
modalPage.off(Page.shownModallyEvent, onShownModal);
}
let modalLoaded = 0;
var onModalLoaded = function (args: EventData) {
modalLoaded++;
modalPage.off(Page.loadedEvent, onModalLoaded);
}
let modalUnloaded = 0;
var onModalUnloaded = function (args: EventData) {
modalUnloaded++;
modalPage.off(Page.unloadedEvent, onModalUnloaded);
TKUnit.assertNull(masterPage.modal, "currentPage.modal should be undefined when no modal page is shown!");
}
var navigatedToEventHandler = function (args) {
let page = <Page>args.object;
TKUnit.assertNull(page.modal, "currentPage.modal should be undefined when no modal page is shown!");
let basePath = "ui/page/";
modalPage = page.showModal(basePath + "modal-page", ctx, modalCloseCallback, false);
TKUnit.assertTrue((<any>modalPage).showingModally, "showingModally");
modalPage.on(Page.shownModallyEvent, onShownModal);
modalPage.on(Page.loadedEvent, onModalLoaded);
modalPage.on(Page.unloadedEvent, onModalUnloaded);
};
var masterPageFactory = function (): Page {
masterPage = new Page();
masterPage.id = "newPage";
masterPage.on(Page.navigatedToEvent, navigatedToEventHandler);
var label = new Label();
label.text = "Text";
masterPage.content = label;
return masterPage;
};
try {
helper.navigate(masterPageFactory);
TKUnit.waitUntilReady(() => { return modalUnloaded > 0; });
TKUnit.assertEqual(shownModally, 1, "shownModally");
TKUnit.assertEqual(modalLoaded, 1,"modalLoaded");
TKUnit.assertEqual(modalUnloaded,1 , "modalUnloaded");
masterPage.off(Page.navigatedToEvent, navigatedToEventHandler);
}
finally {
helper.goBack();
}
}
export function test_WhenShowingModalPageUnloadedIsNotFiredForTheMasterPage() { export function test_WhenShowingModalPageUnloadedIsNotFiredForTheMasterPage() {
let masterPage: Page; let masterPage: Page;
let masterPageUnloaded = false; let masterPageUnloaded = false;

View File

@ -50,6 +50,7 @@ export class Page extends ContentView implements dts.Page {
public static showingModallyEvent = "showingModally"; public static showingModallyEvent = "showingModally";
protected _closeModalCallback: Function; protected _closeModalCallback: Function;
private _modalContext: any;
private _navigationContext: any; private _navigationContext: any;
@ -250,9 +251,11 @@ export class Page extends ContentView implements dts.Page {
protected _showNativeModalView(parent: Page, context: any, closeCallback: Function, fullscreen?: boolean) { protected _showNativeModalView(parent: Page, context: any, closeCallback: Function, fullscreen?: boolean) {
parent._modal = this; parent._modal = this;
var that = this; var that = this;
this._modalContext = context;
this._closeModalCallback = function () { this._closeModalCallback = function () {
if (that._closeModalCallback) { if (that._closeModalCallback) {
that._closeModalCallback = null; that._closeModalCallback = null;
that._modalContext = null;
that._hideNativeModalView(parent); that._hideNativeModalView(parent);
if (typeof closeCallback === "function") { if (typeof closeCallback === "function") {
closeCallback.apply(undefined, arguments); closeCallback.apply(undefined, arguments);
@ -265,20 +268,24 @@ export class Page extends ContentView implements dts.Page {
// //
} }
protected _raiseShownModallyEvent(parent: Page, context: any, closeCallback: Function) { protected _raiseShownModallyEvent() {
this.notify({ let args: dts.ShownModallyData = {
eventName: Page.shownModallyEvent, eventName: Page.shownModallyEvent,
object: this, object: this,
context: context, context: this._modalContext,
closeCallback: this._closeModalCallback closeCallback: this._closeModalCallback
}); }
this.notify(args);
} }
protected _raiseShowingModallyEvent() { protected _raiseShowingModallyEvent() {
this.notify({ let args: dts.ShownModallyData = {
eventName: Page.showingModallyEvent, eventName: Page.showingModallyEvent,
object: this object: this,
}); context: this._modalContext,
closeCallback: this._closeModalCallback
}
this.notify(args);
} }
public _getStyleScope(): styleScope.StyleScope { public _getStyleScope(): styleScope.StyleScope {

View File

@ -25,23 +25,23 @@ function ensureColor() {
export var DIALOG_FRAGMENT_TAG = "dialog"; export var DIALOG_FRAGMENT_TAG = "dialog";
var DialogFragmentClass; interface DialogFragmentClass {
new (owner: Page, fullscreen: boolean, shownCallback: () => void, dismissCallback: () => void): android.app.DialogFragment;
}
var DialogFragmentClass: DialogFragmentClass;
function ensureDialogFragmentClass() { function ensureDialogFragmentClass() {
if (DialogFragmentClass) { if (DialogFragmentClass) {
return; return;
} }
class DialogFragmentClassInner extends android.app.DialogFragment { class DialogFragmentClassInner extends android.app.DialogFragment {
private _owner: Page; constructor(
private _fullscreen: boolean; private _owner: Page,
private _dismissCallback: Function; private _fullscreen: boolean,
private _shownCallback: () => void,
constructor(owner: Page, fullscreen?: boolean, dismissCallback?: Function) { private _dismissCallback: () => void) {
super(); super();
this._owner = owner;
this._fullscreen = fullscreen;
this._dismissCallback = dismissCallback;
return global.__native(this); return global.__native(this);
} }
@ -66,10 +66,29 @@ function ensureDialogFragmentClass() {
return dialog; return dialog;
} }
public onDismiss() { public onStart() {
if (typeof this._dismissCallback === "function") { super.onStart();
this._dismissCallback(); if (!this._owner.isLoaded) {
this._owner.onLoaded();
} }
this._shownCallback();
}
public onDestroyView() {
super.onDestroyView();
if (this._owner.isLoaded) {
this._owner.onUnloaded();
}
this._owner._isAddedToNativeVisualTree = false;
this._owner._onDetached(true);
}
public onDismiss(dialog: android.content.IDialogInterface) {
super.onDismiss(dialog);
this._dismissCallback();
} }
}; };
@ -146,26 +165,20 @@ export class Page extends pageCommon.Page {
this._onAttached(parent._context); this._onAttached(parent._context);
this._isAddedToNativeVisualTree = true; this._isAddedToNativeVisualTree = true;
this.onLoaded();
ensureDialogFragmentClass(); ensureDialogFragmentClass();
var that = this;
this._dialogFragment = new DialogFragmentClass(this, fullscreen, function () { this._dialogFragment = new DialogFragmentClass(this, !!fullscreen, () => this._raiseShownModallyEvent(), () => this.closeModal());
that.closeModal();
});
super._raiseShowingModallyEvent(); super._raiseShowingModallyEvent();
this._dialogFragment.show(parent.frame.android.activity.getFragmentManager(), DIALOG_FRAGMENT_TAG); this._dialogFragment.show(parent.frame.android.activity.getFragmentManager(), DIALOG_FRAGMENT_TAG);
super._raiseShownModallyEvent(parent, context, closeCallback);
} }
protected _hideNativeModalView(parent: Page) { protected _hideNativeModalView(parent: Page) {
this._dialogFragment.dismissAllowingStateLoss(); this._dialogFragment.dismissAllowingStateLoss();
this._dialogFragment = null; this._dialogFragment = null;
this.onUnloaded();
this._isAddedToNativeVisualTree = false;
this._onDetached(true);
parent._modal = undefined; parent._modal = undefined;
super._hideNativeModalView(parent); super._hideNativeModalView(parent);

2
ui/page/page.d.ts vendored
View File

@ -166,7 +166,7 @@ declare module "ui/page" {
/** /**
* Raised before the page is shown as a modal dialog. * Raised before the page is shown as a modal dialog.
*/ */
on(event: "showingModally", callback: (args: observable.EventData) => void, thisArg?: any): void; on(event: "showingModally", callback: (args: ShownModallyData) => void, thisArg?: any): void;
/** /**
* Raised after the page is shown as a modal dialog. * Raised after the page is shown as a modal dialog.

View File

@ -340,7 +340,7 @@ export class Page extends pageCommon.Page {
var that = this; var that = this;
parent.ios.presentViewControllerAnimatedCompletion(this._ios, utils.ios.MajorVersion >= 8, null); parent.ios.presentViewControllerAnimatedCompletion(this._ios, utils.ios.MajorVersion >= 8, null);
UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion.call(parent.ios.transitionCoordinator(), null, function () { UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion.call(parent.ios.transitionCoordinator(), null, function () {
that._raiseShownModallyEvent(parent, context, closeCallback); that._raiseShownModallyEvent();
}); });
} }