From d129dc590405ae9ebc326e843beec1be813934cf Mon Sep 17 00:00:00 2001 From: vakrilov Date: Thu, 24 Mar 2016 14:40:55 +0200 Subject: [PATCH 1/2] ShownModally fired when the dialog is actually shown in Android --- ui/page/page-common.ts | 21 ++++++++++++++------- ui/page/page.android.ts | 42 +++++++++++++++++++++-------------------- ui/page/page.d.ts | 2 +- ui/page/page.ios.ts | 2 +- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/ui/page/page-common.ts b/ui/page/page-common.ts index 95d9961d7..84103d613 100644 --- a/ui/page/page-common.ts +++ b/ui/page/page-common.ts @@ -50,6 +50,7 @@ export class Page extends ContentView implements dts.Page { public static showingModallyEvent = "showingModally"; protected _closeModalCallback: Function; + private _modalContext: 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) { parent._modal = this; var that = this; + this._modalContext = context; this._closeModalCallback = function () { if (that._closeModalCallback) { that._closeModalCallback = null; + that._modalContext = null; that._hideNativeModalView(parent); if (typeof closeCallback === "function") { closeCallback.apply(undefined, arguments); @@ -265,20 +268,24 @@ export class Page extends ContentView implements dts.Page { // } - protected _raiseShownModallyEvent(parent: Page, context: any, closeCallback: Function) { - this.notify({ + protected _raiseShownModallyEvent() { + let args: dts.ShownModallyData = { eventName: Page.shownModallyEvent, object: this, - context: context, + context: this._modalContext, closeCallback: this._closeModalCallback - }); + } + this.notify(args); } protected _raiseShowingModallyEvent() { - this.notify({ + let args: dts.ShownModallyData = { eventName: Page.showingModallyEvent, - object: this - }); + object: this, + context: this._modalContext, + closeCallback: this._closeModalCallback + } + this.notify(args); } public _getStyleScope(): styleScope.StyleScope { diff --git a/ui/page/page.android.ts b/ui/page/page.android.ts index f3d185a74..896714288 100644 --- a/ui/page/page.android.ts +++ b/ui/page/page.android.ts @@ -25,23 +25,23 @@ function ensureColor() { export var DIALOG_FRAGMENT_TAG = "dialog"; -var DialogFragmentClass; -function ensureDialogFragmentClass() { +interface DialogFragmentClass { + new (owner: Page, fullscreen: boolean, shownCallback: () => void, dismissCallback: () => void): android.app.DialogFragment; +} +var DialogFragmentClass: DialogFragmentClass; + +function ensureDialogFragmentClass() { if (DialogFragmentClass) { return; } class DialogFragmentClassInner extends android.app.DialogFragment { - private _owner: Page; - private _fullscreen: boolean; - private _dismissCallback: Function; - - constructor(owner: Page, fullscreen?: boolean, dismissCallback?: Function) { + constructor( + private _owner: Page, + private _fullscreen: boolean, + private _shownCallback: () => void, + private _dismissCallback: () => void) { super(); - - this._owner = owner; - this._fullscreen = fullscreen; - this._dismissCallback = dismissCallback; return global.__native(this); } @@ -66,10 +66,14 @@ function ensureDialogFragmentClass() { return dialog; } - public onDismiss() { - if (typeof this._dismissCallback === "function") { - this._dismissCallback(); - } + public onStart() { + super.onStart(); + this._shownCallback(); + } + + public onDismiss(dialog: android.content.IDialogInterface) { + super.onDismiss(dialog); + this._dismissCallback(); } }; @@ -149,14 +153,12 @@ export class Page extends pageCommon.Page { this.onLoaded(); ensureDialogFragmentClass(); - var that = this; - this._dialogFragment = new DialogFragmentClass(this, fullscreen, function () { - that.closeModal(); - }); + + this._dialogFragment = new DialogFragmentClass(this, !!fullscreen, () => this._raiseShownModallyEvent, () => this.closeModal()); super._raiseShowingModallyEvent(); + this._dialogFragment.show(parent.frame.android.activity.getFragmentManager(), DIALOG_FRAGMENT_TAG); - super._raiseShownModallyEvent(parent, context, closeCallback); } protected _hideNativeModalView(parent: Page) { diff --git a/ui/page/page.d.ts b/ui/page/page.d.ts index f2d6c0eb9..f22b4d179 100644 --- a/ui/page/page.d.ts +++ b/ui/page/page.d.ts @@ -166,7 +166,7 @@ declare module "ui/page" { /** * 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. diff --git a/ui/page/page.ios.ts b/ui/page/page.ios.ts index 63a79f164..ec5c151a2 100644 --- a/ui/page/page.ios.ts +++ b/ui/page/page.ios.ts @@ -340,7 +340,7 @@ export class Page extends pageCommon.Page { var that = this; parent.ios.presentViewControllerAnimatedCompletion(this._ios, utils.ios.MajorVersion >= 8, null); UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion.call(parent.ios.transitionCoordinator(), null, function () { - that._raiseShownModallyEvent(parent, context, closeCallback); + that._raiseShownModallyEvent(); }); } From acb3640a396a1f8def85d3553270c17b9527de8b Mon Sep 17 00:00:00 2001 From: vakrilov Date: Thu, 24 Mar 2016 17:14:19 +0200 Subject: [PATCH 2/2] Test + additional fixes --- apps/tests/ui/page/page-tests-common.ts | 73 +++++++++++++++++++++++++ apps/tests/ui/page/page-tests.ios.ts | 72 +----------------------- ui/page/page.android.ts | 21 +++++-- 3 files changed, 90 insertions(+), 76 deletions(-) diff --git a/apps/tests/ui/page/page-tests-common.ts b/apps/tests/ui/page/page-tests-common.ts index 6e2b621ab..f7872467f 100644 --- a/apps/tests/ui/page/page-tests-common.ts +++ b/apps/tests/ui/page/page-tests-common.ts @@ -28,6 +28,9 @@ import stackLayoutModule = require("ui/layouts/stack-layout"); import helper = require("../helper"); import view = require("ui/core/view"); 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) { var label = new LabelModule.Label(); @@ -440,6 +443,76 @@ export function test_WhenNavigatingForwardAndBack_IsBackNavigationIsCorrect() { 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 = 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((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() { // var testPage: PageModule.Page; // var label: LabelModule.Label; diff --git a/apps/tests/ui/page/page-tests.ios.ts b/apps/tests/ui/page/page-tests.ios.ts index 22e09744a..0758e5959 100644 --- a/apps/tests/ui/page/page-tests.ios.ts +++ b/apps/tests/ui/page/page-tests.ios.ts @@ -1,5 +1,5 @@ import PageTestCommon = require("./page-tests-common"); -import {Page, ShownModallyData} from "ui/page"; +import {Page} from "ui/page"; import TKUnit = require("../../TKUnit"); import {Label} from "ui/label"; 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"); } -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 = 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((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() { let masterPage: Page; let masterPageUnloaded = false; diff --git a/ui/page/page.android.ts b/ui/page/page.android.ts index 896714288..0216c1314 100644 --- a/ui/page/page.android.ts +++ b/ui/page/page.android.ts @@ -68,8 +68,23 @@ function ensureDialogFragmentClass() { public onStart() { super.onStart(); + 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); @@ -150,11 +165,10 @@ export class Page extends pageCommon.Page { this._onAttached(parent._context); this._isAddedToNativeVisualTree = true; - this.onLoaded(); ensureDialogFragmentClass(); - this._dialogFragment = new DialogFragmentClass(this, !!fullscreen, () => this._raiseShownModallyEvent, () => this.closeModal()); + this._dialogFragment = new DialogFragmentClass(this, !!fullscreen, () => this._raiseShownModallyEvent(), () => this.closeModal()); super._raiseShowingModallyEvent(); @@ -165,9 +179,6 @@ export class Page extends pageCommon.Page { this._dialogFragment.dismissAllowingStateLoss(); this._dialogFragment = null; - this.onUnloaded(); - this._isAddedToNativeVisualTree = false; - this._onDetached(true); parent._modal = undefined; super._hideNativeModalView(parent);