From b00013f35ed61e378a8d6620a5801cc280f57b60 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sun, 26 Jul 2020 13:32:44 -0700 Subject: [PATCH] chore: wip es2017 - android build experiment - discuss --- .travis.yml | 7 +- .../core/application/application-common.ts | 43 +-- packages/core/application/index.android.ts | 80 +++-- packages/core/application/index.ios.ts | 4 +- packages/core/globals/index.d.ts | 5 + packages/core/globals/index.ts | 35 ++ packages/core/index.ts | 6 +- packages/core/ui/core/view/index.android.ts | 305 ++++++++++++------ packages/core/ui/frame/activity.android.ts | 147 ++++++--- packages/core/ui/frame/index.android.ts | 55 +++- 10 files changed, 462 insertions(+), 225 deletions(-) diff --git a/.travis.yml b/.travis.yml index 04b9e596f..68d22c7ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,10 @@ language: node_js node_js: - "node" script: -- npm run setup -- nx run core:unit -- nx run core:build.npm +- npm i +- npm start setup +- npm start packages.core.test +- npm start packages.core.build # public API changes check # - npm run api-extractor-ci diff --git a/packages/core/application/application-common.ts b/packages/core/application/application-common.ts index d149a03ec..fe14c4fc4 100644 --- a/packages/core/application/application-common.ts +++ b/packages/core/application/application-common.ts @@ -1,8 +1,7 @@ // Require globals first so that snapshot takes __extends function. -// apply polyfills first -import { initGlobal } from '../globals'; +const nsGlobals = require('../globals'); if (!(global).hasInitGlobal) { - initGlobal(); + nsGlobals.initGlobal(); } // Types @@ -13,32 +12,14 @@ import { View } from '../ui/core/view'; // Requires import { Observable } from '../data/observable'; -import { trace as profilingTrace, time, uptime, level as profilingLevel } from '../profiling'; import * as bindableResources from '../ui/core/bindable/bindable-resources'; import { CSSUtils } from '../css/system-classes'; import { Enums } from '../ui/enums'; export * from './application-interfaces'; -const events = new Observable(); -let launched = false; -function setLaunched() { - launched = true; - events.off('launch', setLaunched); -} -events.on('launch', setLaunched); - -if (profilingLevel() > 0) { - events.on('displayed', () => { - const duration = uptime(); - const end = time(); - const start = end - duration; - profilingTrace(`Displayed in ${duration.toFixed(2)}ms`, start, end); - }); -} - export function hasLaunched(): boolean { - return launched; + return (global).NativeScriptGlobals && (global).NativeScriptGlobals.launched; } export const launchEvent = 'launch'; @@ -69,10 +50,10 @@ export function setResources(res: any) { export let android: AndroidApplication = undefined; export let ios: iOSApplication = undefined; -export const on: typeof events.on = events.on.bind(events); -export const off: typeof events.off = events.off.bind(events); -export const notify: typeof events.notify = events.notify.bind(events); -export const hasListeners: typeof events.hasListeners = events.hasListeners.bind(events); +export const on = (global).NativeScriptGlobals.events.on.bind((global).NativeScriptGlobals.events); +export const off = (global).NativeScriptGlobals.events.off.bind((global).NativeScriptGlobals.events); +export const notify = (global).NativeScriptGlobals.events.notify.bind((global).NativeScriptGlobals.events); +export const hasListeners = (global).NativeScriptGlobals.events.hasListeners.bind((global).NativeScriptGlobals.events); let app: iOSApplication | AndroidApplication; export function setApplication(instance: iOSApplication | AndroidApplication): void { @@ -80,7 +61,7 @@ export function setApplication(instance: iOSApplication | AndroidApplication): v } export function livesync(rootView: View, context?: ModuleContext) { - events.notify({ eventName: 'livesync', object: app }); + (global).NativeScriptGlobals.events.notify({ eventName: 'livesync', object: app }); const liveSyncCore = global.__onLiveSyncCore; let reapplyAppStyles = false; @@ -102,7 +83,7 @@ export function livesync(rootView: View, context?: ModuleContext) { export function setCssFileName(cssFileName: string) { cssFile = cssFileName; - events.notify({ + (global).NativeScriptGlobals.events.notify({ eventName: 'cssChanged', object: app, cssFile: cssFileName, @@ -115,7 +96,7 @@ export function getCssFileName(): string { export function loadAppCss(): void { try { - events.notify({ + (global).NativeScriptGlobals.events.notify({ eventName: 'loadAppCss', object: app, cssFile: getCssFileName(), @@ -181,7 +162,7 @@ export function systemAppearanceChanged(rootView: View, newSystemAppearance: 'da } global.__onUncaughtError = function (error: NativeScriptError) { - events.notify({ + (global).NativeScriptGlobals.events.notify({ eventName: uncaughtErrorEvent, object: app, android: error, @@ -191,7 +172,7 @@ global.__onUncaughtError = function (error: NativeScriptError) { }; global.__onDiscardedError = function (error: NativeScriptError) { - events.notify({ + (global).NativeScriptGlobals.events.notify({ eventName: discardedErrorEvent, object: app, error: error, diff --git a/packages/core/application/index.android.ts b/packages/core/application/index.android.ts index 6fa1585d9..b95fbe401 100644 --- a/packages/core/application/index.android.ts +++ b/packages/core/application/index.android.ts @@ -5,8 +5,8 @@ import { View } from '../ui/core/view'; import { NavigationEntry, AndroidActivityCallbacks } from '../ui/frame/frame-interfaces'; import { Observable } from '../data/observable'; -// Requires -import { displayedEvent, hasListeners, livesync, lowMemoryEvent, notify, orientationChanged, orientationChangedEvent, setApplication, suspendEvent, systemAppearanceChanged, systemAppearanceChangedEvent } from './application-common'; +// Use requires to ensure order of imports is maintained +const appCommon = require('./application-common'); // First reexport so that app module is initialized. export * from './application-common'; @@ -60,9 +60,12 @@ export class AndroidApplication extends Observable implements AndroidApplication this.nativeApp = nativeApp; this.packageName = nativeApp.getPackageName(); this.context = nativeApp.getApplicationContext(); - + console.log('this.nativeApp:', this.nativeApp); + console.log('this.packageName:', this.packageName); + console.log('this.context:', this.context); // we store those callbacks and add a function for clearing them later so that the objects will be eligable for GC this.callbacks.lifecycleCallbacks = initLifecycleCallbacks(); + console.log('this.callbacks.lifecycleCallbacks:', this.callbacks.lifecycleCallbacks); this.callbacks.componentCallbacks = initComponentCallbacks(); this.nativeApp.registerActivityLifecycleCallbacks(this.callbacks.lifecycleCallbacks); this.nativeApp.registerComponentCallbacks(this.callbacks.componentCallbacks); @@ -154,8 +157,7 @@ export interface AndroidApplication { const androidApp = new AndroidApplication(); export { androidApp as android }; - -setApplication(androidApp); +appCommon.setApplication(androidApp); let mainEntry: NavigationEntry; let started = false; @@ -167,6 +169,8 @@ export function run(entry?: NavigationEntry | string) { started = true; mainEntry = typeof entry === 'string' ? { moduleName: entry } : entry; + console.log('run mainEntry:', mainEntry); + console.log('androidApp.nativeApp:', androidApp.nativeApp); if (!androidApp.nativeApp) { const nativeApp = getNativeApplication(); androidApp.init(nativeApp); @@ -174,7 +178,7 @@ export function run(entry?: NavigationEntry | string) { } export function addCss(cssText: string, attributeScoped?: boolean): void { - notify({ + appCommon.notify({ eventName: 'cssChanged', object: androidApp, cssText: cssText, @@ -263,7 +267,7 @@ global.__onLiveSync = function __onLiveSync(context?: ModuleContext) { } const rootView = getRootView(); - livesync(rootView, context); + appCommon.livesync(rootView, context); }; function getOrientationValue(configuration: android.content.res.Configuration): 'portrait' | 'landscape' | 'unknown' { @@ -318,8 +322,8 @@ function initLifecycleCallbacks() { // store the listener not to trigger GC collection before collecting the method global.onGlobalLayoutListener = new android.view.ViewTreeObserver.OnGlobalLayoutListener({ onGlobalLayout() { - notify({ - eventName: displayedEvent, + appCommon.notify({ + eventName: appCommon.displayedEvent, object: androidApp, activity, }); @@ -340,7 +344,7 @@ function initLifecycleCallbacks() { notifyActivityCreated(activity, savedInstanceState, undefined); - if (hasListeners(displayedEvent)) { + if (appCommon.hasListeners(appCommon.displayedEvent)) { subscribeForGlobalLayout(activity, undefined, undefined); } }), @@ -366,8 +370,8 @@ function initLifecycleCallbacks() { onActivityPaused: profile('onActivityPaused', function (activity: androidx.appcompat.app.AppCompatActivity) { if ((activity).isNativeScriptActivity) { androidApp.paused = true; - notify({ - eventName: suspendEvent, + appCommon.notify({ + eventName: appCommon.suspendEvent, object: androidApp, android: activity, }); @@ -424,8 +428,8 @@ function initComponentCallbacks() { onLowMemory: profile('onLowMemory', function () { gc(); java.lang.System.gc(); - notify({ - eventName: lowMemoryEvent, + appCommon.notify({ + eventName: appCommon.lowMemoryEvent, object: this, android: this, }); @@ -441,10 +445,10 @@ function initComponentCallbacks() { if (androidApp.orientation !== newOrientation) { androidApp.orientation = newOrientation; - orientationChanged(rootView, newOrientation); + appCommon.orientationChanged(rootView, newOrientation); - notify({ - eventName: orientationChangedEvent, + appCommon.notify({ + eventName: appCommon.orientationChangedEvent, android: androidApp.nativeApp, newValue: androidApp.orientation, object: androidApp, @@ -457,10 +461,10 @@ function initComponentCallbacks() { if (androidApp.systemAppearance !== newSystemAppearance) { androidApp.systemAppearance = newSystemAppearance; - systemAppearanceChanged(rootView, newSystemAppearance); + appCommon.systemAppearanceChanged(rootView, newSystemAppearance); - notify({ - eventName: systemAppearanceChangedEvent, + appCommon.notify({ + eventName: appCommon.systemAppearanceChangedEvent, android: androidApp.nativeApp, newValue: androidApp.systemAppearance, object: androidApp, @@ -478,23 +482,37 @@ function ensureBroadCastReceiverClass() { return; } - @NativeClass - class BroadcastReceiver extends android.content.BroadcastReceiver { - private _onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void; + // @NativeClass + // class BroadcastReceiver extends android.content.BroadcastReceiver { + // private _onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void; - constructor(onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) { - super(); - this._onReceiveCallback = onReceiveCallback; + // constructor(onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) { + // super(); + // this._onReceiveCallback = onReceiveCallback; - return global.__native(this); + // return global.__native(this); + // } + + // public onReceive(context: android.content.Context, intent: android.content.Intent) { + // if (this._onReceiveCallback) { + // this._onReceiveCallback(context, intent); + // } + // } + // } + var BroadcastReceiver = (function (_super) { + __extends(BroadcastReceiver, _super); + function BroadcastReceiver(onReceiveCallback) { + var _this = _super.call(this) || this; + _this._onReceiveCallback = onReceiveCallback; + return global.__native(_this); } - - public onReceive(context: android.content.Context, intent: android.content.Intent) { + BroadcastReceiver.prototype.onReceive = function (context, intent) { if (this._onReceiveCallback) { this._onReceiveCallback(context, intent); } - } - } + }; + return BroadcastReceiver; + })(android.content.BroadcastReceiver); BroadcastReceiverClass = BroadcastReceiver; } diff --git a/packages/core/application/index.ios.ts b/packages/core/application/index.ios.ts index a47e94fd4..ba05b941a 100644 --- a/packages/core/application/index.ios.ts +++ b/packages/core/application/index.ios.ts @@ -2,8 +2,8 @@ import { iOSApplication as iOSApplicationDefinition } from '.'; import { ApplicationEventData, CssChangedEventData, LaunchEventData, LoadAppCSSEventData, OrientationChangedEventData, SystemAppearanceChangedEventData } from './application-interfaces'; -// Require -import { displayedEvent, exitEvent, getCssFileName, launchEvent, livesync, lowMemoryEvent, notify, on, orientationChanged, orientationChangedEvent, resumeEvent, setApplication, suspendEvent, systemAppearanceChanged, systemAppearanceChangedEvent } from './application-common'; +// Use requires to ensure order of imports is maintained +const { displayedEvent, exitEvent, getCssFileName, launchEvent, livesync, lowMemoryEvent, notify, on, orientationChanged, orientationChangedEvent, resumeEvent, setApplication, suspendEvent, systemAppearanceChanged, systemAppearanceChangedEvent } = require('./application-common'); // First reexport so that app module is initialized. export * from './application-common'; diff --git a/packages/core/globals/index.d.ts b/packages/core/globals/index.d.ts index c1ea0392a..34b248a72 100644 --- a/packages/core/globals/index.d.ts +++ b/packages/core/globals/index.d.ts @@ -1,2 +1,7 @@ +import { Observable } from '../data/observable'; +export declare class NativeScriptGlobalState { + events: Observable; + launched: boolean; +} export function installPolyfills(moduleName: string, exportNames: string[]): void; export function initGlobal(): void; diff --git a/packages/core/globals/index.ts b/packages/core/globals/index.ts index 480524d1e..5a8770d86 100644 --- a/packages/core/globals/index.ts +++ b/packages/core/globals/index.ts @@ -1,6 +1,8 @@ import * as tslibType from 'tslib'; const tslib: typeof tslibType = require('tslib'); import { isIOS, isAndroid } from '../platform'; +import { Observable } from '../data/observable'; +import { trace as profilingTrace, time, uptime, level as profilingLevel } from '../profiling'; type ModuleLoader = (name?: string) => any; @@ -33,6 +35,36 @@ function registerOnGlobalContext(moduleName: string, exportName: string): void { }); } +/** + * Manages internal framework global state + */ +export class NativeScriptGlobalState { + events: Observable; + launched = false; + private _setLaunched: () => void; + constructor() { + // console.log('creating NativeScriptGlobals...') + this.events = new Observable(); + this._setLaunched = this._setLaunchedFn.bind(this); + this.events.on('launch', this._setLaunched); + if (profilingLevel() > 0) { + this.events.on('displayed', () => { + const duration = uptime(); + const end = time(); + const start = end - duration; + profilingTrace(`Displayed in ${duration.toFixed(2)}ms`, start, end); + }); + } + } + + private _setLaunchedFn() { + // console.log('NativeScriptGlobals launch fired!'); + this.launched = true; + this.events.off('launch', this._setLaunched); + this._setLaunched = null; + } +} + export function installPolyfills(moduleName: string, exportNames: string[]) { if (global.__snapshot) { const loadedModule = global.loadModule(moduleName); @@ -45,6 +77,9 @@ export function installPolyfills(moduleName: string, exportNames: string[]) { export function initGlobal() { if (!(global).hasInitGlobal) { (global).hasInitGlobal = true; + // init global state handler + (global).NativeScriptGlobals = new NativeScriptGlobalState(); + // ts-helpers // Required by V8 snapshot generator if (!(global).__extends) { diff --git a/packages/core/index.ts b/packages/core/index.ts index 3c0cf5f68..4289d38f5 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -1,8 +1,8 @@ /// -// Init globals first -import { initGlobal } from './globals'; -initGlobal(); +// Init globals first (use require to ensure it's always at the top) +const nsGlobals = require('./globals'); +nsGlobals.initGlobal(); // Export all interfaces from "application" module export { ApplicationEventData, LaunchEventData, OrientationChangedEventData, UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData, iOSApplication, AndroidApplication, AndroidActivityEventData, AndroidActivityBundleEventData, AndroidActivityRequestPermissionsEventData, AndroidActivityResultEventData, AndroidActivityNewIntentEventData, AndroidActivityBackPressedEventData } from './application'; diff --git a/packages/core/ui/core/view/index.android.ts b/packages/core/ui/core/view/index.android.ts index 8967488cc..4b3f826f2 100644 --- a/packages/core/ui/core/view/index.android.ts +++ b/packages/core/ui/core/view/index.android.ts @@ -122,68 +122,212 @@ function initializeTouchListener(): void { TouchListener = TouchListenerImpl; } +// function initializeDialogFragment() { +// if (DialogFragment) { +// return; +// } + +// @NativeClass +// class DialogImpl extends android.app.Dialog { +// constructor(public fragment: DialogFragmentImpl, context: android.content.Context, themeResId: number) { +// super(context, themeResId); + +// return global.__native(this); +// } + +// public onDetachedFromWindow(): void { +// super.onDetachedFromWindow(); +// this.fragment = null; +// } + +// public onBackPressed(): void { +// const view = this.fragment.owner; +// const args = { +// eventName: 'activityBackPressed', +// object: view, +// activity: view._context, +// cancel: false, +// }; + +// // Fist fire application.android global event +// androidApp.notify(args); +// if (args.cancel) { +// return; +// } + +// view.notify(args); + +// if (!args.cancel && !view.onBackPressed()) { +// super.onBackPressed(); +// } +// } +// } + +// class DialogFragmentImpl extends androidx.fragment.app.DialogFragment { +// public owner: View; +// private _fullscreen: boolean; +// private _animated: boolean; +// private _stretched: boolean; +// private _cancelable: boolean; +// private _shownCallback: () => void; +// private _dismissCallback: () => void; + +// constructor() { +// super(); + +// return global.__native(this); +// } + +// public onCreateDialog(savedInstanceState: android.os.Bundle): android.app.Dialog { +// const ownerId = this.getArguments().getInt(DOMID); +// const options = getModalOptions(ownerId); +// this.owner = options.owner; +// // Set owner._dialogFragment to this in case the DialogFragment was recreated after app suspend +// this.owner._dialogFragment = this; +// this._fullscreen = options.fullscreen; +// this._animated = options.animated; +// this._cancelable = options.cancelable; +// this._stretched = options.stretched; +// this._dismissCallback = options.dismissCallback; +// this._shownCallback = options.shownCallback; +// this.setStyle(androidx.fragment.app.DialogFragment.STYLE_NO_TITLE, 0); + +// let theme = this.getTheme(); +// if (this._fullscreen) { +// // In fullscreen mode, get the application's theme. +// theme = this.getActivity().getApplicationInfo().theme; +// } + +// const dialog = new DialogImpl(this, this.getActivity(), theme); + +// // do not override alignment unless fullscreen modal will be shown; +// // otherwise we might break component-level layout: +// // https://github.com/NativeScript/NativeScript/issues/5392 +// if (!this._fullscreen && !this._stretched) { +// this.owner.horizontalAlignment = 'center'; +// this.owner.verticalAlignment = 'middle'; +// } else { +// this.owner.horizontalAlignment = 'stretch'; +// this.owner.verticalAlignment = 'stretch'; +// } + +// // set the modal window animation +// // https://github.com/NativeScript/NativeScript/issues/5989 +// if (this._animated) { +// dialog.getWindow().setWindowAnimations(styleAnimationDialog); +// } + +// dialog.setCanceledOnTouchOutside(this._cancelable); + +// return dialog; +// } + +// public onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View { +// const owner = this.owner; +// owner._setupAsRootView(this.getActivity()); +// owner._isAddedToNativeVisualTree = true; + +// return owner.nativeViewProtected; +// } + +// public onStart(): void { +// super.onStart(); +// if (this._fullscreen) { +// const window = this.getDialog().getWindow(); +// const length = android.view.ViewGroup.LayoutParams.MATCH_PARENT; +// window.setLayout(length, length); +// // This removes the default backgroundDrawable so there are no margins. +// window.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.WHITE)); +// } + +// const owner = this.owner; +// if (owner && !owner.isLoaded) { +// owner.callLoaded(); +// } + +// this._shownCallback(); +// } + +// public onDismiss(dialog: android.content.DialogInterface): void { +// super.onDismiss(dialog); +// const manager = this.getFragmentManager(); +// if (manager) { +// removeModal(this.owner._domId); +// this._dismissCallback(); +// } + +// const owner = this.owner; +// if (owner && owner.isLoaded) { +// owner.callUnloaded(); +// } +// } + +// public onDestroy(): void { +// super.onDestroy(); +// const owner = this.owner; + +// if (owner) { +// // Android calls onDestroy before onDismiss. +// // Make sure we unload first and then call _tearDownUI. +// if (owner.isLoaded) { +// owner.callUnloaded(); +// } + +// owner._isAddedToNativeVisualTree = false; +// owner._tearDownUI(true); +// } +// } +// } + +// DialogFragment = DialogFragmentImpl; +// } function initializeDialogFragment() { if (DialogFragment) { return; } - - @NativeClass - class DialogImpl extends android.app.Dialog { - constructor(public fragment: DialogFragmentImpl, context: android.content.Context, themeResId: number) { - super(context, themeResId); - - return global.__native(this); + var DialogImpl = (function (_super) { + __extends(DialogImpl, _super); + function DialogImpl(fragment, context, themeResId) { + var _this = _super.call(this, context, themeResId) || this; + _this.fragment = fragment; + return global.__native(_this); } - - public onDetachedFromWindow(): void { - super.onDetachedFromWindow(); + DialogImpl.prototype.onDetachedFromWindow = function () { + _super.prototype.onDetachedFromWindow.call(this); this.fragment = null; - } - - public onBackPressed(): void { - const view = this.fragment.owner; - const args = { + }; + DialogImpl.prototype.onBackPressed = function () { + var view = this.fragment.owner; + if (!view) { + return; + } + var args = { eventName: 'activityBackPressed', object: view, activity: view._context, cancel: false, }; - - // Fist fire application.android global event - androidApp.notify(args); + application_1.android.notify(args); if (args.cancel) { return; } - view.notify(args); - if (!args.cancel && !view.onBackPressed()) { - super.onBackPressed(); + _super.prototype.onBackPressed.call(this); } + }; + return DialogImpl; + })(android.app.Dialog); + var DialogFragmentImpl = (function (_super) { + __extends(DialogFragmentImpl, _super); + function DialogFragmentImpl() { + var _this = _super.call(this) || this; + return global.__native(_this); } - } - - class DialogFragmentImpl extends androidx.fragment.app.DialogFragment { - public owner: View; - private _fullscreen: boolean; - private _animated: boolean; - private _stretched: boolean; - private _cancelable: boolean; - private _shownCallback: () => void; - private _dismissCallback: () => void; - - constructor() { - super(); - - return global.__native(this); - } - - public onCreateDialog(savedInstanceState: android.os.Bundle): android.app.Dialog { - const ownerId = this.getArguments().getInt(DOMID); - const options = getModalOptions(ownerId); + DialogFragmentImpl.prototype.onCreateDialog = function (savedInstanceState) { + var ownerId = this.getArguments().getInt(DOMID); + var options = getModalOptions(ownerId); this.owner = options.owner; - // Set owner._dialogFragment to this in case the DialogFragment was recreated after app suspend - this.owner._dialogFragment = this; this._fullscreen = options.fullscreen; this._animated = options.animated; this._cancelable = options.cancelable; @@ -191,18 +335,11 @@ function initializeDialogFragment() { this._dismissCallback = options.dismissCallback; this._shownCallback = options.shownCallback; this.setStyle(androidx.fragment.app.DialogFragment.STYLE_NO_TITLE, 0); - - let theme = this.getTheme(); + var theme = this.getTheme(); if (this._fullscreen) { - // In fullscreen mode, get the application's theme. theme = this.getActivity().getApplicationInfo().theme; } - - const dialog = new DialogImpl(this, this.getActivity(), theme); - - // do not override alignment unless fullscreen modal will be shown; - // otherwise we might break component-level layout: - // https://github.com/NativeScript/NativeScript/issues/5392 + var dialog = new DialogImpl(this, this.getActivity(), theme); if (!this._fullscreen && !this._stretched) { this.owner.horizontalAlignment = 'center'; this.owner.verticalAlignment = 'middle'; @@ -210,75 +347,57 @@ function initializeDialogFragment() { this.owner.horizontalAlignment = 'stretch'; this.owner.verticalAlignment = 'stretch'; } - - // set the modal window animation - // https://github.com/NativeScript/NativeScript/issues/5989 if (this._animated) { dialog.getWindow().setWindowAnimations(styleAnimationDialog); } - dialog.setCanceledOnTouchOutside(this._cancelable); - return dialog; - } - - public onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View { - const owner = this.owner; + }; + DialogFragmentImpl.prototype.onCreateView = function (inflater, container, savedInstanceState) { + var owner = this.owner; owner._setupAsRootView(this.getActivity()); owner._isAddedToNativeVisualTree = true; - return owner.nativeViewProtected; - } - - public onStart(): void { - super.onStart(); + }; + DialogFragmentImpl.prototype.onStart = function () { + _super.prototype.onStart.call(this); if (this._fullscreen) { - const window = this.getDialog().getWindow(); - const length = android.view.ViewGroup.LayoutParams.MATCH_PARENT; - window.setLayout(length, length); - // This removes the default backgroundDrawable so there are no margins. - window.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.WHITE)); + var window_1 = this.getDialog().getWindow(); + var length_1 = android.view.ViewGroup.LayoutParams.MATCH_PARENT; + window_1.setLayout(length_1, length_1); + window_1.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.WHITE)); } - - const owner = this.owner; + var owner = this.owner; if (owner && !owner.isLoaded) { owner.callLoaded(); } - this._shownCallback(); - } - - public onDismiss(dialog: android.content.DialogInterface): void { - super.onDismiss(dialog); - const manager = this.getFragmentManager(); + }; + DialogFragmentImpl.prototype.onDismiss = function (dialog) { + _super.prototype.onDismiss.call(this, dialog); + var manager = this.getFragmentManager(); if (manager) { removeModal(this.owner._domId); this._dismissCallback(); } - - const owner = this.owner; + var owner = this.owner; if (owner && owner.isLoaded) { owner.callUnloaded(); } - } - - public onDestroy(): void { - super.onDestroy(); - const owner = this.owner; - + }; + DialogFragmentImpl.prototype.onDestroy = function () { + _super.prototype.onDestroy.call(this); + var owner = this.owner; if (owner) { - // Android calls onDestroy before onDismiss. - // Make sure we unload first and then call _tearDownUI. if (owner.isLoaded) { owner.callUnloaded(); } - owner._isAddedToNativeVisualTree = false; owner._tearDownUI(true); } - } - } - + }; + return DialogFragmentImpl; + })(androidx.fragment.app.DialogFragment); DialogFragment = DialogFragmentImpl; } diff --git a/packages/core/ui/frame/activity.android.ts b/packages/core/ui/frame/activity.android.ts index 9f92d2c5c..6bea70a03 100644 --- a/packages/core/ui/frame/activity.android.ts +++ b/packages/core/ui/frame/activity.android.ts @@ -1,69 +1,124 @@ import { setActivityCallbacks, AndroidActivityCallbacks } from '.'; -import { initGlobal } from '../../globals'; -import * as appModule from '../../application'; +// use requires to ensure import order +const globals = require('../../globals'); +const appModule = require('../../application'); if (global.__snapshot) { - initGlobal(); + globals.initGlobal(); } - -const superProto = androidx.appcompat.app.AppCompatActivity.prototype; -// @JavaProxy('com.tns.NativeScriptActivity') -const NativeScriptActivity = (androidx.appcompat.app.AppCompatActivity).extend('com.tns.NativeScriptActivity', { - init() { - // superProto(); - // return global.__native(this); - }, - onCreate(savedInstanceState: android.os.Bundle): void { - console.log('onCreate this.getApplication():', this.getApplication()); +/** + * Option 1: the exact es5 compiled version of what this normally looks like + */ +var NativeScriptActivity = (function (_super) { + __extends(NativeScriptActivity, _super); + function NativeScriptActivity() { + console.log('construct NativeScriptActivity'); + var _this = _super.call(this) || this; + return global.__native(_this); + } + NativeScriptActivity.prototype.init = function () { + // return new NativeScriptActivity(); + }; + NativeScriptActivity.prototype.onCreate = function (savedInstanceState) { appModule.android.init(this.getApplication()); - - // Set isNativeScriptActivity in onCreate. - // The JS constructor might not be called because the activity is created from Android. this.isNativeScriptActivity = true; if (!this._callbacks) { setActivityCallbacks(this); } + this._callbacks.onCreate(this, savedInstanceState, this.getIntent(), _super.prototype.onCreate); + }; + NativeScriptActivity.prototype.onNewIntent = function (intent) { + this._callbacks.onNewIntent(this, intent, _super.prototype.setIntent, _super.prototype.onNewIntent); + }; + NativeScriptActivity.prototype.onSaveInstanceState = function (outState) { + this._callbacks.onSaveInstanceState(this, outState, _super.prototype.onSaveInstanceState); + }; + NativeScriptActivity.prototype.onStart = function () { + this._callbacks.onStart(this, _super.prototype.onStart); + }; + NativeScriptActivity.prototype.onStop = function () { + this._callbacks.onStop(this, _super.prototype.onStop); + }; + NativeScriptActivity.prototype.onDestroy = function () { + this._callbacks.onDestroy(this, _super.prototype.onDestroy); + }; + NativeScriptActivity.prototype.onPostResume = function () { + this._callbacks.onPostResume(this, _super.prototype.onPostResume); + }; + NativeScriptActivity.prototype.onBackPressed = function () { + this._callbacks.onBackPressed(this, _super.prototype.onBackPressed); + }; + NativeScriptActivity.prototype.onRequestPermissionsResult = function (requestCode, permissions, grantResults) { + this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined); + }; + NativeScriptActivity.prototype.onActivityResult = function (requestCode, resultCode, data) { + this._callbacks.onActivityResult(this, requestCode, resultCode, data, _super.prototype.onActivityResult); + }; + NativeScriptActivity = __decorate([JavaProxy('com.tns.NativeScriptActivity')], NativeScriptActivity); + return NativeScriptActivity; +})(androidx.appcompat.app.AppCompatActivity); - this._callbacks.onCreate(this, savedInstanceState, this.getIntent(), superProto.onCreate); - }, +// Option 2: the manual es5 way - results in same as above +// const superProto = androidx.appcompat.app.AppCompatActivity.prototype; +// const NativeScriptActivity = (androidx.appcompat.app.AppCompatActivity).extend('com.tns.NativeScriptActivity', { +// init() { +// // superProto(); +// // return global.__native(this); +// }, +// onCreate(savedInstanceState: android.os.Bundle): void { +// appModule.android.init(this.getApplication()); - onNewIntent(intent: android.content.Intent): void { - this._callbacks.onNewIntent(this, intent, superProto.setIntent, superProto.onNewIntent); - }, +// // Set isNativeScriptActivity in onCreate. +// // The JS constructor might not be called because the activity is created from Android. +// this.isNativeScriptActivity = true; +// if (!this._callbacks) { +// setActivityCallbacks(this); +// } - onSaveInstanceState(outState: android.os.Bundle): void { - this._callbacks.onSaveInstanceState(this, outState, superProto.onSaveInstanceState); - }, +// this._callbacks.onCreate(this, savedInstanceState, this.getIntent(), superProto.onCreate); +// }, - onStart(): void { - this._callbacks.onStart(this, superProto.onStart); - }, +// onNewIntent(intent: android.content.Intent): void { +// this._callbacks.onNewIntent(this, intent, superProto.setIntent, superProto.onNewIntent); +// }, - onStop(): void { - this._callbacks.onStop(this, superProto.onStop); - }, +// onSaveInstanceState(outState: android.os.Bundle): void { +// this._callbacks.onSaveInstanceState(this, outState, superProto.onSaveInstanceState); +// }, - onDestroy(): void { - this._callbacks.onDestroy(this, superProto.onDestroy); - }, +// onStart(): void { +// this._callbacks.onStart(this, superProto.onStart); +// }, - onPostResume(): void { - this._callbacks.onPostResume(this, superProto.onPostResume); - }, +// onStop(): void { +// this._callbacks.onStop(this, superProto.onStop); +// }, - onBackPressed(): void { - this._callbacks.onBackPressed(this, superProto.onBackPressed); - }, +// onDestroy(): void { +// this._callbacks.onDestroy(this, superProto.onDestroy); +// }, - onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { - this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); - }, +// onPostResume(): void { +// this._callbacks.onPostResume(this, superProto.onPostResume); +// }, - onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { - this._callbacks.onActivityResult(this, requestCode, resultCode, data, superProto.onActivityResult); - }, -}); +// onBackPressed(): void { +// this._callbacks.onBackPressed(this, superProto.onBackPressed); +// }, +// onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { +// this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); +// }, + +// onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { +// this._callbacks.onActivityResult(this, requestCode, resultCode, data, superProto.onActivityResult); +// }, +// }); + +/** + * Option 3: The way which worked when using es5 compile target however when targeting es2017, this source code won't work due to the extends from native class so trying options 1 and 2 to achieve same + */ +// @JavaProxy('com.tns.NativeScriptActivity') // class NativeScriptActivity extends androidx.appcompat.app.AppCompatActivity { // private _callbacks: AndroidActivityCallbacks; // public isNativeScriptActivity; diff --git a/packages/core/ui/frame/index.android.ts b/packages/core/ui/frame/index.android.ts index 61d212ca9..c222d0734 100644 --- a/packages/core/ui/frame/index.android.ts +++ b/packages/core/ui/frame/index.android.ts @@ -48,28 +48,49 @@ export let attachStateChangeListener: android.view.View.OnAttachStateChangeListe function getAttachListener(): android.view.View.OnAttachStateChangeListener { if (!attachStateChangeListener) { - const AttachListener = (java.lang.Object).extend({ - interfaces: [android.view.View.OnAttachStateChangeListener], - init() { - // this.super(this); - // return global.__native(this); - }, - onViewAttachedToWindow(view: android.view.View): void { - // console.log('onViewAttachedToWindow') - const owner: View = view[ownerSymbol]; - // console.log('owner:', owner) + var AttachListener = (function (_super) { + __extends(AttachListener, _super); + function AttachListener() { + var _this = _super.call(this) || this; + return global.__native(_this); + } + AttachListener.prototype.onViewAttachedToWindow = function (view) { + var owner = view[ownerSymbol]; if (owner) { - // console.log('owner._onAttachedToWindow:', owner._onAttachedToWindow) owner._onAttachedToWindow(); } - }, - onViewDetachedFromWindow(view: android.view.View): void { - const owner: View = view[ownerSymbol]; + }; + AttachListener.prototype.onViewDetachedFromWindow = function (view) { + var owner = view[ownerSymbol]; if (owner) { owner._onDetachedFromWindow(); } - }, - }); + }; + AttachListener = __decorate([Interfaces([android.view.View.OnAttachStateChangeListener])], AttachListener); + return AttachListener; + })(java.lang.Object); + // const AttachListener = (java.lang.Object).extend({ + // interfaces: [android.view.View.OnAttachStateChangeListener], + // init() { + // // this.super(this); + // // return global.__native(this); + // }, + // onViewAttachedToWindow(view: android.view.View): void { + // console.log('onViewAttachedToWindow') + // const owner: View = view[ownerSymbol]; + // console.log('owner:', owner) + // if (owner) { + // // console.log('owner._onAttachedToWindow:', owner._onAttachedToWindow) + // owner._onAttachedToWindow(); + // } + // }, + // onViewDetachedFromWindow(view: android.view.View): void { + // const owner: View = view[ownerSymbol]; + // if (owner) { + // owner._onDetachedFromWindow(); + // } + // }, + // }); // class AttachListener extends java.lang.Object implements android.view.View.OnAttachStateChangeListener { // constructor() { // super(); @@ -93,6 +114,7 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener { // } attachStateChangeListener = new AttachListener(); + console.log('attachStateChangeListener:', attachStateChangeListener); } return attachStateChangeListener; @@ -509,6 +531,7 @@ export class Frame extends FrameBase { super.initNativeView(); const listener = getAttachListener(); console.log('listener:', listener); + console.log(' this.nativeViewProtected:', this.nativeViewProtected); this.nativeViewProtected.addOnAttachStateChangeListener(listener); this.nativeViewProtected[ownerSymbol] = this; this._android.rootViewGroup = this.nativeViewProtected;