From f7d5a8e8a642ad281eb96b30a2076166edecf3b3 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 12 May 2023 16:51:29 +0200 Subject: [PATCH] refactor: additional cleanup and code reuse --- apps/automated/src/main.ts | 110 ++++---- .../core/application/application-common.ts | 246 ++++++++++++++---- .../application/application-interfaces.ts | 4 +- .../core/application/application.android.ts | 60 +++-- packages/core/application/application.ios.ts | 116 +++------ packages/core/ui/frame/index.android.ts | 114 ++------ packages/core/ui/frame/index.ios.ts | 241 +++++++++++++---- packages/core/utils/android/index.ts | 2 +- .../core/utils/mainthread-helper.android.ts | 4 +- 9 files changed, 544 insertions(+), 353 deletions(-) diff --git a/apps/automated/src/main.ts b/apps/automated/src/main.ts index b4cba0987..3a4e804c7 100644 --- a/apps/automated/src/main.ts +++ b/apps/automated/src/main.ts @@ -16,6 +16,8 @@ import { AndroidActivityNewIntentEventData, AndroidActivityResultEventData, AndroidActivityBackPressedEventData, + Label, + LaunchEventData, } from '@nativescript/core'; // import * as Application from "@nativescript/core/application"; @@ -25,7 +27,7 @@ if (Application.ios) { Application.ios.addNotificationObserver( UIApplicationDidFinishLaunchingNotification, (notification: NSNotification) => { - console.log('UIApplicationDidFinishLaunchingNotification: ' + notification); + console.log('UIApplicationDidFinishLaunchingNotification:', notification); } ); } @@ -35,77 +37,75 @@ Application.on(Application.displayedEvent, function (args: ApplicationEventData) global.isDisplayedEventFired = true; if (args.android) { - // For Android applications, args.android is an Android activity class. - console.log('Displayed Activity: ' + args.android); + // For Android applications, args.activity is an Android activity class. + console.log('Displayed Activity:', (args as AndroidActivityEventData).activity); } else if (args.ios) { // For iOS applications, args.ios is UIApplication. - console.log('Displayed UIApplication: ' + args.ios); + console.log('Displayed UIApplication:', args.ios); } }); -Application.on(Application.launchEvent, function (args: ApplicationEventData) { +Application.on(Application.launchEvent, function (args: LaunchEventData) { if (args.android) { // For Android applications, args.android is an android.content.Intent class. - console.log( - 'Launched Android application with the following intent: ' + args.android + '.' - ); + console.log('Launched Android application with the following intent:', args.android); } else if (args.ios !== undefined) { // For iOS applications, args.ios is NSDictionary (launchOptions). - console.log('Launched iOS application with options: ' + args.ios); + console.log('Launched iOS application with options:', args.ios); } }); Application.on(Application.suspendEvent, function (args: ApplicationEventData) { if (args.android) { // For Android applications, args.android is an Android activity class. - console.log('Suspend Activity: ' + args.android); + console.log('Suspend Activity:', args.android); } else if (args.ios) { // For iOS applications, args.ios is UIApplication. - console.log('Suspend UIApplication: ' + args.ios); + console.log('Suspend UIApplication:', args.ios); } }); Application.on(Application.resumeEvent, function (args: ApplicationEventData) { if (args.android) { // For Android applications, args.android is an Android activity class. - console.log('Resume Activity: ' + args.android); + console.log('Resume Activity:', args.android); } else if (args.ios) { // For iOS applications, args.ios is UIApplication. - console.log('Resume UIApplication: ' + args.ios); + console.log('Resume UIApplication:', args.ios); } }); Application.on(Application.exitEvent, function (args: ApplicationEventData) { if (args.android) { // For Android applications, args.android is an Android activity class. - console.log('Exit Activity: ' + args.android); + console.log('Exit Activity:', args.android); } else if (args.ios) { // For iOS applications, args.ios is UIApplication. - console.log('Exit UIApplication: ' + args.ios); + console.log('Exit UIApplication:', args.ios); } }); Application.on(Application.lowMemoryEvent, function (args: ApplicationEventData) { if (args.android) { // For Android applications, args.android is an Android activity class. - console.log('Low Memory: ' + args.android); + console.log('Low Memory:', args.android); } else if (args.ios) { // For iOS applications, args.ios is UIApplication. - console.log('Low Memory: ' + args.ios); + console.log('Low Memory:', args.ios); } }); // Error events. Application.on(Application.uncaughtErrorEvent, function (args: UnhandledErrorEventData) { - console.log('NativeScriptError: ' + args.error); - console.log((args.error).nativeException || (args.error).nativeError); - console.log((args.error).stackTrace || (args.error).stack); + console.log('NativeScriptError:', args.error); + console.log((args.error).nativeException ?? (args.error).nativeError); + console.log((args.error).stackTrace ?? (args.error).stack); }); Application.on(Application.discardedErrorEvent, function (args: DiscardedErrorEventData) { - console.log('[Discarded] NativeScriptError: ' + args.error); - console.log((args.error).nativeException || (args.error).nativeError); - console.log((args.error).stackTrace || (args.error).stack); + console.log('[Discarded] NativeScriptError:', args.error); + console.log((args.error).nativeException ?? (args.error).nativeError); + console.log((args.error).stackTrace ?? (args.error).stack); }); // Android activity events. @@ -114,12 +114,10 @@ if (Application.android) { Application.android.activityCreatedEvent, function (args: AndroidActivityBundleEventData) { console.log( - 'Event: ' + - args.eventName + - ', Activity: ' + - args.activity + - ', Bundle: ' + - args.bundle + 'Event: ' + args.eventName + ', Activity:', + args.activity, + ', Bundle:', + args.bundle ); } ); @@ -127,35 +125,35 @@ if (Application.android) { Application.android.on( Application.android.activityDestroyedEvent, function (args: AndroidActivityEventData) { - console.log('Event: ' + args.eventName + ', Activity: ' + args.activity); + console.log('Event: ' + args.eventName + ', Activity: ', args.activity); } ); Application.android.on( Application.android.activityStartedEvent, function (args: AndroidActivityEventData) { - console.log('Event: ' + args.eventName + ', Activity: ' + args.activity); + console.log('Event: ' + args.eventName + ', Activity:', args.activity); } ); Application.android.on( Application.android.activityPausedEvent, function (args: AndroidActivityEventData) { - console.log('Event: ' + args.eventName + ', Activity: ' + args.activity); + console.log('Event: ' + args.eventName + ', Activity:', args.activity); } ); Application.android.on( Application.android.activityResumedEvent, function (args: AndroidActivityEventData) { - console.log('Event: ' + args.eventName + ', Activity: ' + args.activity); + console.log('Event: ' + args.eventName + ', Activity:', args.activity); } ); Application.android.on( Application.android.activityStoppedEvent, function (args: AndroidActivityEventData) { - console.log('Event: ' + args.eventName + ', Activity: ' + args.activity); + console.log('Event: ' + args.eventName + ', Activity:', args.activity); } ); @@ -163,12 +161,10 @@ if (Application.android) { Application.android.saveActivityStateEvent, function (args: AndroidActivityBundleEventData) { console.log( - 'Event: ' + - args.eventName + - ', Activity: ' + - args.activity + - ', Bundle: ' + - args.bundle + 'Event: ' + args.eventName + ', Activity:', + args.activity, + ', Bundle:', + args.bundle ); } ); @@ -177,16 +173,16 @@ if (Application.android) { Application.android.activityResultEvent, function (args: AndroidActivityResultEventData) { console.log( - 'Event: ' + - args.eventName + - ', Activity: ' + - args.activity + - ', requestCode: ' + - args.requestCode + - ', resultCode: ' + - args.resultCode + - ', Intent: ' + - args.intent + 'Event:', + args.eventName, + ', Activity:', + args.activity, + ', requestCode: ', + args.requestCode, + ', resultCode: ', + args.resultCode, + ', Intent: ', + args.intent ); } ); @@ -194,7 +190,7 @@ if (Application.android) { Application.android.on( Application.android.activityBackPressedEvent, function (args: AndroidActivityBackPressedEventData) { - console.log('Event: ' + args.eventName + ', Activity: ' + args.activity); + console.log('Event:', args.eventName, ', Activity:', args.activity); // Set args.cancel = true to cancel back navigation and do something custom. } ); @@ -203,12 +199,12 @@ if (Application.android) { Application.android.activityNewIntentEvent, function (args: AndroidActivityNewIntentEventData) { console.log( - 'Event: ' + - args.eventName + - ', Activity: ' + - args.activity + - ', Intent: ' + - args.intent + 'Event: ', + args.eventName, + ', Activity:', + args.activity, + ', Intent:', + args.intent ); } ); diff --git a/packages/core/application/application-common.ts b/packages/core/application/application-common.ts index e30455d05..dbde20d17 100644 --- a/packages/core/application/application-common.ts +++ b/packages/core/application/application-common.ts @@ -1,19 +1,28 @@ -// Require globals first so that snapshot takes __extends function. -// import '../globals'; - -import { Observable } from '../data/observable'; +import { initAccessibilityCssHelper } from '../accessibility/accessibility-css-helper'; +import { initAccessibilityFontScale } from '../accessibility/font-scale'; import { CoreTypes } from '../core-types'; import { CSSUtils } from '../css/system-classes'; +import { Observable } from '../data/observable'; +import { Device } from '../platform'; +import { profile } from '../profiling'; import { Trace } from '../trace'; +import { Builder } from '../ui/builder'; import * as bindableResources from '../ui/core/bindable/bindable-resources'; -import { View } from '../ui/core/view'; +import type { View } from '../ui/core/view'; +import type { Frame } from '../ui/frame'; import { NavigationEntry } from '../ui/frame/frame-interfaces'; +import type { StyleScope } from '../ui/styling/style-scope'; import type { AndroidApplication as IAndroidApplication, iOSApplication as IiOSApplication, } from './'; -import { CssChangedEventData, LoadAppCSSEventData } from './application-interfaces'; import { + ApplicationEventData, + CssChangedEventData, + DiscardedErrorEventData, + LaunchEventData, + LoadAppCSSEventData, + NativeScriptError, OrientationChangedEventData, SystemAppearanceChangedEventData, } from './application-interfaces'; @@ -43,22 +52,75 @@ export class ApplicationCommon extends Observable { readonly orientationChangedEvent = 'orientationChanged'; readonly systemAppearanceChangedEvent = 'systemAppearanceChanged'; readonly fontScaleChangedEvent = 'fontScaleChanged'; + readonly livesyncEvent = 'livesync'; constructor() { super(); global.NativeScriptGlobals.appInstanceReady = true; + + global.__onUncaughtError = (error: NativeScriptError) => { + this.notify({ + eventName: this.uncaughtErrorEvent, + object: this, + android: error, + ios: error, + error: error, + } as DiscardedErrorEventData); + }; + + global.__onDiscardedError = (error: NativeScriptError) => { + this.notify({ + eventName: this.discardedErrorEvent, + object: this, + error: error, + } as DiscardedErrorEventData); + }; + + global.__onLiveSync = (context?: ModuleContext) => { + if (this.suspended) { + return; + } + + const rootView = this.getRootView(); + this.livesync(rootView, context); + }; + } + + livesync(rootView: View, context?: ModuleContext) { + this.notify({ eventName: this.livesyncEvent, object: this }); + const liveSyncCore = global.__onLiveSyncCore; + let reapplyAppStyles = false; + + // ModuleContext is available only for Hot Module Replacement + if (context && context.path) { + const styleExtensions = ['css', 'scss']; + const appStylesFullFileName = this.getCssFileName(); + const appStylesFileName = appStylesFullFileName.substring( + 0, + appStylesFullFileName.lastIndexOf('.') + 1 + ); + reapplyAppStyles = styleExtensions.some( + (ext) => context.path === appStylesFileName.concat(ext) + ); + } + + // Handle application styles + if (rootView && reapplyAppStyles) { + rootView._onCssStateChange(); + } else if (liveSyncCore) { + liveSyncCore(context); + } } - /** - * Ensure css-class is set on rootView - */ applyCssClass(rootView: View, cssClasses: string[], newCssClass: string): void { if (!rootView.cssClasses.has(newCssClass)) { cssClasses.forEach((cssClass) => this.removeCssClass(rootView, cssClass)); this.addCssClass(rootView, newCssClass); this.increaseStyleScopeApplicationCssSelectorVersion(rootView); rootView._onCssStateChange(); + + console.log('APPLY ROOT CSS CLASSES', ...rootView.cssClasses); } } @@ -73,15 +135,41 @@ export class ApplicationCommon extends Observable { } private increaseStyleScopeApplicationCssSelectorVersion(rootView: View) { - const styleScope = - rootView._styleScope || - ((rootView).currentPage && (rootView).currentPage._styleScope); + const styleScope: StyleScope = + rootView._styleScope ?? (rootView as Frame)?.currentPage?._styleScope; if (styleScope) { styleScope._increaseApplicationCssSelectorVersion(); } } + protected setRootViewCSSClasses(rootView: View): void { + const platform = Device.os.toLowerCase(); + const deviceType = Device.deviceType.toLowerCase(); + + if (platform) { + CSSUtils.pushToSystemCssClasses(`${CSSUtils.CLASS_PREFIX}${platform}`); + } + + if (deviceType) { + CSSUtils.pushToSystemCssClasses(`${CSSUtils.CLASS_PREFIX}${deviceType}`); + } + + if (this.orientation) { + CSSUtils.pushToSystemCssClasses(`${CSSUtils.CLASS_PREFIX}${this.orientation}`); + } + + if (this.systemAppearance) { + CSSUtils.pushToSystemCssClasses(`${CSSUtils.CLASS_PREFIX}${this.systemAppearance}`); + } + + rootView.cssClasses.add(CSSUtils.ROOT_VIEW_CSS_CLASS); + const rootViewCssClasses = CSSUtils.getSystemCssClasses(); + rootViewCssClasses.forEach((c) => rootView.cssClasses.add(c)); + + console.log('ROOT CSS CLASSES', ...rootView.cssClasses); + } + /** * iOS Only * Dynamically change the preferred frame rate @@ -89,12 +177,14 @@ export class ApplicationCommon extends Observable { * For devices (iOS < 15), you can specify the max frame rate * see: https://developer.apple.com/documentation/quartzcore/optimizing_promotion_refresh_rates_for_iphone_13_pro_and_ipad_pro * To use, ensure your Info.plist has: + * ```xml * CADisableMinimumFrameDurationOnPhone * + * ``` * @param options { min?: number; max?: number; preferred?: number } */ setMaxRefreshRate(options?: { min?: number; max?: number; preferred?: number }) { - // + // implement in platform specific files (iOS only for now) } mainEntry: NavigationEntry; @@ -102,15 +192,62 @@ export class ApplicationCommon extends Observable { return this.mainEntry; } + @profile + protected notifyLaunch(additionalLanchEventData?: any): View | null { + const launchArgs: LaunchEventData = { + eventName: this.launchEvent, + object: this, + ios: this.ios, + android: this.android, + ...additionalLanchEventData, + }; + this.notify(launchArgs); + this.loadAppCss(); + + return launchArgs.root; + } + + createRootView(view?: View, fireLaunchEvent = false, additionalLanchEventData?: any) { + let rootView = view; + + if (!rootView) { + if (fireLaunchEvent) { + rootView = this.notifyLaunch(additionalLanchEventData); + + // useful for integrations that would like to set rootView asynchronously after app launch + if (rootView === null) { + return null; + } + } + + if (!rootView) { + // try to navigate to the mainEntry (if specified) + if (!this.mainEntry) { + throw new Error( + 'Main entry is missing. App cannot be started. Verify app bootstrap.' + ); + } + + rootView = Builder.createViewFromEntry(this.mainEntry); + } + } + + return rootView; + } + getRootView(): View { - // ensureNativeApplication(); - // return iosApp.rootView; - // return this.rootView; throw new Error('getRootView() Not implemented.'); } resetRootView(entry?: NavigationEntry | string) { this.mainEntry = typeof entry === 'string' ? { moduleName: entry } : entry; + // rest of implementation is platform specific + } + + initRootView() { + this.setRootViewCSSClasses(this.getRootView()); + initAccessibilityCssHelper(); + initAccessibilityFontScale(); } /** @@ -157,7 +294,9 @@ export class ApplicationCommon extends Observable { try { this.notify({ eventName: 'loadAppCss', - object: this, // app, + object: this, + ios: this.ios, + android: this.android, cssFile: this.getCssFileName(), }); } catch (e) { @@ -174,7 +313,7 @@ export class ApplicationCommon extends Observable { addCss(cssText: string, attributeScoped?: boolean): void { this.notify({ eventName: 'cssChanged', - object: this, // iosApp, + object: this, cssText: cssText, }); if (!attributeScoped) { @@ -250,9 +389,9 @@ export class ApplicationCommon extends Observable { return global.NativeScriptGlobals && global.NativeScriptGlobals.launched; } - private _systemAppearance: 'dark' | 'light'; + private _systemAppearance: 'dark' | 'light' | null; - protected getSystemAppearance(): 'dark' | 'light' { + protected getSystemAppearance(): 'dark' | 'light' | null { // override in platform specific Application class throw new Error('getSystemAppearance() not implemented'); } @@ -262,7 +401,6 @@ export class ApplicationCommon extends Observable { return; } this._systemAppearance = value; - this.setRootViewsSystemAppearanceCssClass(this.getRootView()); this.systemAppearanceChanged(this.getRootView(), value); this.notify({ eventName: this.systemAppearanceChangedEvent, @@ -273,14 +411,7 @@ export class ApplicationCommon extends Observable { }); } - setRootViewsSystemAppearanceCssClass(rootView: View): void { - const systemAppearance = this.systemAppearance; - const systemAppearanceCssClass = `${CSSUtils.CLASS_PREFIX}${systemAppearance}`; - CSSUtils.pushToSystemCssClasses(systemAppearanceCssClass); - rootView.cssClasses.add(systemAppearanceCssClass); - } - - get systemAppearance(): 'dark' | 'light' { + get systemAppearance(): 'dark' | 'light' | null { // return cached value, or get it from the platform specific override return (this._systemAppearance ??= this.getSystemAppearance()); } @@ -314,16 +445,55 @@ export class ApplicationCommon extends Observable { newSystemAppearanceCssClass ); - const rootModalViews = >rootView._getRootModalViews(); + const rootModalViews = rootView._getRootModalViews(); rootModalViews.forEach((rootModalView) => { this.applyCssClass( - rootModalView, + rootModalView as View, SYSTEM_APPEARANCE_CSS_CLASSES, newSystemAppearanceCssClass ); }); } + private _inBackground: boolean = false; + + get inBackground() { + return this._inBackground; + } + + setInBackground(value: boolean, additonalData?: any) { + this._inBackground = value; + + this.notify({ + eventName: value ? this.backgroundEvent : this.foregroundEvent, + object: this, + ios: this.ios, + + ...additonalData, + }); + } + + private _suspended: boolean = false; + + get suspended() { + return this._suspended; + } + + setSuspended(value: boolean, additonalData?: any) { + this._suspended = value; + + this.notify({ + eventName: value ? this.suspendEvent : this.resumeEvent, + object: this, + ios: this.ios, + android: this.android, + + ...additonalData, + }); + } + + public started = false; + get android(): IAndroidApplication { return undefined; } @@ -332,18 +502,6 @@ export class ApplicationCommon extends Observable { return undefined; } - get inBackground() { - return false; - } - - get suspended() { - return false; - } - - setSuspended(suspended: boolean) { - // TODO - } - get AndroidApplication() { return this.android; } @@ -351,8 +509,6 @@ export class ApplicationCommon extends Observable { get iOSApplication() { return this.ios; } - - public started = false; } // export const AndroidApplication: IAndroidApplication = undefined; diff --git a/packages/core/application/application-interfaces.ts b/packages/core/application/application-interfaces.ts index 007d5f990..d6e2d49ef 100644 --- a/packages/core/application/application-interfaces.ts +++ b/packages/core/application/application-interfaces.ts @@ -84,7 +84,7 @@ export interface FontScaleChangedEventData extends ApplicationEventData { /** * Event data containing information about unhandled application errors. */ -export interface UnhandledErrorEventData extends EventData { +export interface UnhandledErrorEventData extends ApplicationEventData { ios?: NativeScriptError; android?: NativeScriptError; error: NativeScriptError; @@ -93,7 +93,7 @@ export interface UnhandledErrorEventData extends EventData { /** * Event data containing information about discarded application errors. */ -export interface DiscardedErrorEventData extends EventData { +export interface DiscardedErrorEventData extends ApplicationEventData { error: NativeScriptError; } diff --git a/packages/core/application/application.android.ts b/packages/core/application/application.android.ts index 299544e86..c0d486f79 100644 --- a/packages/core/application/application.android.ts +++ b/packages/core/application/application.android.ts @@ -1,15 +1,13 @@ -import { initAccessibilityCssHelper } from '../accessibility/accessibility-css-helper'; -import { initAccessibilityFontScale } from '../accessibility/font-scale'; import { profile } from '../profiling'; import { View } from '../ui'; import { AndroidActivityCallbacks, NavigationEntry } from '../ui/frame/frame-common'; +import type { AndroidApplication as IAndroidApplication } from './application'; +import { ApplicationCommon } from './application-common'; import type { AndroidActivityBundleEventData, AndroidActivityEventData, ApplicationEventData, - AndroidApplication as IAndroidApplication, -} from '.'; -import { ApplicationCommon } from './application-common'; +} from './application-interfaces'; declare namespace com { namespace tns { @@ -102,18 +100,18 @@ class NativeScriptLifecycleCallbacks extends android.app.Application } as AndroidActivityEventData); // TODO: This is a temporary workaround to force the V8's Garbage Collector, which will force the related Java Object to be collected. - // gc(); + gc(); } @profile public onActivityPaused(activity: androidx.appcompat.app.AppCompatActivity): void { // console.log('NativeScriptLifecycleCallbacks onActivityPaused'); if ('isNativeScriptActivity' in activity) { - Application.android.notify({ - eventName: Application.suspendEvent, - object: Application.android, + Application.setSuspended(true, { + // todo: deprecate event.android in favor of event.activity android: activity, - } as ApplicationEventData); + activity, + }); } Application.android.notify({ @@ -128,6 +126,9 @@ class NativeScriptLifecycleCallbacks extends android.app.Application // console.log('NativeScriptLifecycleCallbacks onActivityResumed'); Application.android.setForegroundActivity(activity); + // NOTE: setSuspended(false) is called in frame/index.android.ts inside onPostResume + // This is done to ensure proper timing for the event to be raised + Application.android.notify({ eventName: Application.android.activityResumedEvent, object: Application.android, @@ -227,11 +228,11 @@ class NativeScriptLifecycleCallbacks extends android.app.Application new android.view.ViewTreeObserver.OnGlobalLayoutListener({ onGlobalLayout() { Application.android.notify({ - eventName: Application.android.displayedEvent, + eventName: Application.displayedEvent, object: Application, android: Application.android, activity, - }); + } as AndroidActivityEventData); const viewTreeObserver = rootView.getViewTreeObserver(); viewTreeObserver.removeOnGlobalLayoutListener(global.onGlobalLayoutListener); }, @@ -380,17 +381,6 @@ export class AndroidApplication extends ApplicationCommon implements IAndroidApp const nativeApp = this.getNativeApplication(); this.init(nativeApp); } - - initAccessibilityCssHelper(); - initAccessibilityFontScale(); - } - - /** - * todo: check if true, cause there's no such thing in Utils.android - * @deprecated Use Utils.android.getPackageName() instead. - */ - get packageName() { - return this.nativeApp.getPackageName(); } private _startActivity: androidx.appcompat.app.AppCompatActivity; @@ -412,10 +402,34 @@ export class AndroidApplication extends ApplicationCommon implements IAndroidApp this._foregroundActivity = value; } + /** + * @deprecated Use `Application.suspended` instead. + */ + get paused(): boolean { + return this.suspended; + } + + /** + * @deprecated Use `Application.inBackground` instead. + */ + get backgrounded(): boolean { + return this.inBackground; + } + + /** + * @deprecated Use `Utils.android.getApplicationContext()` instead. + */ get context() { return this.nativeApp.getApplicationContext(); } + /** + * @deprecated Use `Utils.android.getPackageName()` instead. + */ + get packageName() { + return this.nativeApp.getPackageName(); + } + public registerBroadcastReceiver( intentFilter: string, onReceiveCallback: ( diff --git a/packages/core/application/application.ios.ts b/packages/core/application/application.ios.ts index ab7e52b25..3de967205 100644 --- a/packages/core/application/application.ios.ts +++ b/packages/core/application/application.ios.ts @@ -1,12 +1,9 @@ -import { initAccessibilityCssHelper } from '../accessibility/accessibility-css-helper'; -import { initAccessibilityFontScale } from '../accessibility/font-scale'; import { profile } from '../profiling'; import { View } from '../ui'; -import { Builder } from '../ui/builder'; import { IOSHelper } from '../ui/core/view/view-helper'; import { NavigationEntry } from '../ui/frame/frame-interfaces'; import * as Utils from '../utils'; -import type { iOSApplication as IiOSApplication } from './'; +import type { iOSApplication as IiOSApplication } from './application'; import { ApplicationCommon } from './application-common'; import { ApplicationEventData, @@ -35,7 +32,7 @@ class CADisplayLinkTarget extends NSObject { owner.notify({ eventName: owner.displayedEvent, object: owner, - ios: owner.ios, + ios: UIApplication.sharedApplication, }); owner.displayedLinkTarget = null; owner.displayedLink = null; @@ -130,8 +127,6 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication } run(entry?: string | NavigationEntry): void { - console.log('run in iOSApplication', entry); - this.mainEntry = typeof entry === 'string' ? { moduleName: entry } : entry; this.started = true; @@ -140,9 +135,6 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication } else { this.runAsMainApp(); } - - initAccessibilityCssHelper(); - initAccessibilityFontScale(); } private runAsMainApp() { @@ -195,31 +187,10 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication visibleVC.presentViewControllerAnimatedCompletion(controller, true, null); } - // this.setRootViewsSystemAppearanceCssClass(rootView); + this.initRootView(); this.notifyAppStarted(); } - private createRootView(v?: View) { - let rootView = v; - if (!rootView) { - console.log('createRootView mainEntry', this.mainEntry); - // try to navigate to the mainEntry (if specified) - if (!this.mainEntry) { - throw new Error( - 'Main entry is missing. App cannot be started. Verify app bootstrap.' - ); - } else { - // console.log('createRootView mainEntry:', mainEntry); - rootView = Builder.createViewFromEntry(this.mainEntry); - } - } - // console.log('createRootView rootView:', rootView); - - // setRootViewsCssClasses(rootView); - - return rootView; - } - private getViewController(rootView: View): UIViewController { let viewController: UIViewController = rootView.viewController || rootView.ios; @@ -362,8 +333,8 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication protected getSystemAppearance(): 'light' | 'dark' { // userInterfaceStyle is available on UITraitCollection since iOS 12. - if (Utils.ios.MajorVersion <= 11) { - return undefined; + if (Utils.ios.MajorVersion <= 11 || !this.rootController) { + return null; } const userInterfaceStyle = this.rootController.traitCollection.userInterfaceStyle; @@ -399,25 +370,16 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication } private notifyAppStarted(notification?: NSNotification) { - const args: LaunchEventData = { - eventName: this.launchEvent, - object: this, + const root = this.notifyLaunch({ ios: notification?.userInfo?.objectForKey( 'UIApplicationLaunchOptionsLocalNotificationKey' - ) || null, - }; - - this.notify(args); - this.notify({ - eventName: 'loadAppCss', - object: this, - cssFile: this.getCssFileName(), + ) ?? null, }); if (this._window) { - if (args.root !== null && !NativeScriptEmbedder.sharedInstance().delegate) { - this.setWindowContent(args.root); + if (root !== null && !NativeScriptEmbedder.sharedInstance().delegate) { + this.setWindowContent(root); } } else { this._window = UIApplication.sharedApplication.keyWindow; @@ -442,12 +404,12 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication const haveController = this._window.rootViewController !== null; this._window.rootViewController = controller; - this.setRootViewsSystemAppearanceCssClass(rootView); - if (!haveController) { this._window.makeKeyAndVisible(); } + this.initRootView(); + rootView.on(IOSHelper.traitCollectionColorAppearanceChangedEvent, () => { const userInterfaceStyle = controller.traitCollection.userInterfaceStyle; const newSystemAppearance = this.getSystemAppearanceValue(userInterfaceStyle); @@ -474,47 +436,29 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication @profile private didBecomeActive(notification: NSNotification) { - // const ios = UIApplication.sharedApplication; - // const object = this; - // setInBackground(false); - // setSuspended(false); - this.notify({ - eventName: this.resumeEvent, - object: this, - ios: this.ios, - }); - this.notify({ - eventName: this.foregroundEvent, - object: this, - ios: this.ios, - }); - // const rootView = this._rootView; - // if (rootView && !rootView.isLoaded) { - // rootView.callLoaded(); - // } + const additionalData = { + ios: UIApplication.sharedApplication, + }; + this.setInBackground(false, additionalData); + this.setSuspended(false, additionalData); + + const rootView = this._rootView; + if (rootView && !rootView.isLoaded) { + rootView.callLoaded(); + } } private didEnterBackground(notification: NSNotification) { - // const ios = UIApplication.sharedApplication; - // const object = this; - // setInBackground(true); - // setSuspended(true); + const additionalData = { + ios: UIApplication.sharedApplication, + }; + this.setInBackground(true, additionalData); + this.setSuspended(true, additionalData); - this.notify({ - eventName: this.suspendEvent, - object: this, - ios: this.ios, - }); - this.notify({ - eventName: this.backgroundEvent, - object: this, - ios: this.ios, - }); - - // const rootView = this._rootView; - // if (rootView && rootView.isLoaded) { - // rootView.callUnloaded(); - // } + const rootView = this._rootView; + if (rootView && rootView.isLoaded) { + rootView.callUnloaded(); + } } private willTerminate(notification: NSNotification) { diff --git a/packages/core/ui/frame/index.android.ts b/packages/core/ui/frame/index.android.ts index 19b65c73d..0393e787b 100644 --- a/packages/core/ui/frame/index.android.ts +++ b/packages/core/ui/frame/index.android.ts @@ -14,9 +14,6 @@ import { AndroidActivityRequestPermissionsEventData, AndroidActivityResultEventData, Application, - ApplicationEventData, - LaunchEventData, - LoadAppCSSEventData, } from '../../application'; import { _stack, FrameBase, NavigationType } from './frame-common'; @@ -35,17 +32,9 @@ import { addNativeTransitionListener, } from './fragment.transitions'; -// TODO: Remove this and get it from global to decouple builder for angular -import { Builder } from '../builder'; -import { CSSUtils } from '../../css/system-classes'; -import { Device } from '../../platform'; import { profile } from '../../profiling'; -import { ad } from '../../utils/native-helper'; +import { android as androidUtils } from '../../utils/native-helper'; import type { ExpandedEntry } from './fragment.transitions.android'; -import { - SharedTransition, - SharedTransitionAnimationType, -} from '../transition/shared-transition'; import { AndroidActivityBackPressedEventData, AndroidActivityNewIntentEventData, @@ -53,8 +42,6 @@ import { export * from './frame-common'; -const ANDROID_PLATFORM = 'android'; - const INTENT_EXTRA = 'com.tns.activity'; const ROOT_VIEW_ID_EXTRA = 'com.tns.activity.rootViewId'; const FRAMEID = '_frameId'; @@ -123,7 +110,7 @@ export class Frame extends FrameBase { } public static reloadPage(context?: ModuleContext): void { - const activity = ad.getCurrentActivity(); + const activity = androidUtils.getCurrentActivity(); const callbacks: AndroidActivityCallbacks = activity[CALLBACKS]; if (callbacks) { const rootView: View = callbacks.getRootView(); @@ -180,7 +167,7 @@ export class Frame extends FrameBase { // _onAttachedToWindow called from OS again after it was detach // still happens with androidx.fragment:1.3.2 - const activity = ad.getCurrentActivity(); + const activity = androidUtils.getCurrentActivity(); const lifecycleState = activity?.getLifecycle?.()?.getCurrentState() || androidx.lifecycle.Lifecycle.State.CREATED; @@ -1413,13 +1400,11 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { // and raising the application resume event there causes issues like // https://github.com/NativeScript/NativeScript/issues/6708 if ((activity).isNativeScriptActivity) { - Application.setSuspended(false); - const args = { - eventName: Application.resumeEvent, - object: Application.android, + Application.setSuspended(false, { + // todo: deprecate in favor of using event.activity instead. android: activity, - }; - Application.notify(args); + activity, + }); } } @@ -1585,52 +1570,21 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { ); } + const intent = activity.getIntent(); + rootView = Application.createRootView(rootView, fireLaunchEvent, { + // todo: deprecate in favor of args.intent? + android: intent, + intent, + savedInstanceState, + }); + if (!rootView) { - const mainEntry = Application.getMainEntry(); - const intent = activity.getIntent(); - // useful for integrations that would like to set rootView asynchronously after app launch - let shouldRootViewBeEmpty = false; - - if (fireLaunchEvent) { - // entry point for Angular and Vue frameworks - rootView = notifyLaunch(intent, savedInstanceState, null); - shouldRootViewBeEmpty = rootView === null; - } - - if (!rootView) { - if (shouldRootViewBeEmpty) { - return; - } - // entry point for NS Core - if (!mainEntry) { - // Also handles scenarios with Angular and Vue where the notifyLaunch didn't return a root view. - throw new Error( - 'Main entry is missing. App cannot be started. Verify app bootstrap.' - ); - } - - rootView = Builder.createViewFromEntry(mainEntry); - } - - this._rootView = rootView; - activityRootViewsMap.set(rootView._domId, new WeakRef(rootView)); - - const deviceType = Device.deviceType.toLowerCase(); - - CSSUtils.pushToSystemCssClasses(`${CSSUtils.CLASS_PREFIX}${ANDROID_PLATFORM}`); - CSSUtils.pushToSystemCssClasses(`${CSSUtils.CLASS_PREFIX}${deviceType}`); - CSSUtils.pushToSystemCssClasses( - `${CSSUtils.CLASS_PREFIX}${Application.android.orientation}` - ); - CSSUtils.pushToSystemCssClasses( - `${CSSUtils.CLASS_PREFIX}${Application.android.systemAppearance}` - ); - - this._rootView.cssClasses.add(CSSUtils.ROOT_VIEW_CSS_CLASS); - const rootViewCssClasses = CSSUtils.getSystemCssClasses(); - rootViewCssClasses.forEach((c) => this._rootView.cssClasses.add(c)); + // no root view created + return; } + activityRootViewsMap.set(rootView._domId, new WeakRef(rootView)); + // setup view as styleScopeHost rootView._setupAsRootView(activity); @@ -1638,34 +1592,14 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { rootView.nativeViewProtected, new org.nativescript.widgets.CommonLayoutParams() ); + + this._rootView = rootView; + + // sets root classes once rootView is ready... + Application.initRootView(); } } -const notifyLaunch = profile( - 'notifyLaunch', - function notifyLaunch( - intent: android.content.Intent, - savedInstanceState: android.os.Bundle - ): View { - const launchArgs: LaunchEventData = { - eventName: Application.launchEvent, - object: Application, - android: intent, - savedInstanceState, - }; - - Application.notify(launchArgs); - Application.notify({ - eventName: 'loadAppCss', - object: Application, - android: Application.android, - cssFile: Application.getCssFileName(), - }); - - return launchArgs.root; - } -); - export function setActivityCallbacks( activity: androidx.appcompat.app.AppCompatActivity ): void { diff --git a/packages/core/ui/frame/index.ios.ts b/packages/core/ui/frame/index.ios.ts index f01dced4c..a6b4999ca 100644 --- a/packages/core/ui/frame/index.ios.ts +++ b/packages/core/ui/frame/index.ios.ts @@ -5,7 +5,7 @@ import { Page } from '../page'; import { View } from '../core/view'; import { IOSHelper } from '../core/view/view-helper'; import { profile } from '../../profiling'; -import { CORE_ANIMATION_DEFAULTS, iOSNativeHelper, layout } from '../../utils'; +import { CORE_ANIMATION_DEFAULTS, ios as iOSUtils, layout } from '../../utils'; import { Trace } from '../../trace'; import type { PageTransition } from '../transition/page-transition'; import { SlideTransition } from '../transition/slide-transition'; @@ -14,7 +14,7 @@ import { SharedTransition } from '../transition/shared-transition'; export * from './frame-common'; -const majorVersion = iOSNativeHelper.MajorVersion; +const majorVersion = iOSUtils.MajorVersion; const ENTRY = '_entry'; const DELEGATE = '_delegate'; @@ -82,13 +82,17 @@ export class Frame extends FrameBase { navDepth = -1; } - const isReplace = this._executingContext && this._executingContext.navigationType === NavigationType.replace; + const isReplace = + this._executingContext && + this._executingContext.navigationType === NavigationType.replace; if (!isReplace) { navDepth++; } let navigationTransition: NavigationTransition; - const animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false; + const animated = this.currentPage + ? this._getIsAnimatedNavigation(backstackEntry.entry) + : false; if (animated) { navigationTransition = this._getNavigationTransition(backstackEntry.entry); if (navigationTransition) { @@ -102,7 +106,9 @@ export class Frame extends FrameBase { const nativeTransition = _getNativeTransition(navigationTransition, true); if (!nativeTransition && navigationTransition) { if (!this._animatedDelegate) { - this._animatedDelegate = UINavigationControllerAnimatedDelegate.initWithOwner(new WeakRef(this)); + this._animatedDelegate = ( + UINavigationControllerAnimatedDelegate.initWithOwner(new WeakRef(this)) + ); } this._ios.controller.delegate = this._animatedDelegate; viewController[DELEGATE] = this._animatedDelegate; @@ -128,7 +134,12 @@ export class Frame extends FrameBase { if (!animated && majorVersion > 10) { // Reset back button title before pushing view controller to prevent // displaying default 'back' title (when NavigaitonButton custom title is set). - const barButtonItem = UIBarButtonItem.alloc().initWithTitleStyleTargetAction('', UIBarButtonItemStyle.Plain, null, null); + const barButtonItem = UIBarButtonItem.alloc().initWithTitleStyleTargetAction( + '', + UIBarButtonItemStyle.Plain, + null, + null + ); viewController.navigationItem.backBarButtonItem = barButtonItem; } @@ -138,9 +149,16 @@ export class Frame extends FrameBase { this._updateActionBar(backstackEntry.resolvedPage, true); // Core defaults modalPresentationStyle to 1 for standard frame navigation // for all others, it's modal presentation - this.pushViewControllerAnimated(viewController, animated, this._ios?.controller?.modalPresentationStyle !== 1); + this.pushViewControllerAnimated( + viewController, + animated, + this._ios?.controller?.modalPresentationStyle !== 1 + ); if (Trace.isEnabled()) { - Trace.write(`${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, Trace.categories.Navigation); + Trace.write( + `${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, + Trace.categories.Navigation + ); } return; @@ -160,7 +178,10 @@ export class Frame extends FrameBase { this._ios.controller.setViewControllersAnimated(newControllers, animated); if (Trace.isEnabled()) { - Trace.write(`${this}.setViewControllersAnimated([${viewController}], ${animated}); depth = ${navDepth}`, Trace.categories.Navigation); + Trace.write( + `${this}.setViewControllersAnimated([${viewController}], ${animated}); depth = ${navDepth}`, + Trace.categories.Navigation + ); } return; @@ -169,7 +190,9 @@ export class Frame extends FrameBase { // We should hide the current entry from the back stack. // This is the case for HMR when NavigationType.replace. if (!Frame._isEntryBackstackVisible(this._currentEntry) || isReplace) { - const newControllers = NSMutableArray.alloc().initWithArray(this._ios.controller.viewControllers); + const newControllers = NSMutableArray.alloc().initWithArray( + this._ios.controller.viewControllers + ); if (newControllers.count === 0) { throw new Error('Wrong controllers count.'); } @@ -187,7 +210,10 @@ export class Frame extends FrameBase { // replace the controllers instead of pushing directly this._ios.controller.setViewControllersAnimated(newControllers, animated); if (Trace.isEnabled()) { - Trace.write(`${this}.setViewControllersAnimated([originalControllers - lastController + ${viewController}], ${animated}); depth = ${navDepth}`, Trace.categories.Navigation); + Trace.write( + `${this}.setViewControllersAnimated([originalControllers - lastController + ${viewController}], ${animated}); depth = ${navDepth}`, + Trace.categories.Navigation + ); } return; @@ -196,11 +222,18 @@ export class Frame extends FrameBase { // General case. this._ios.controller.pushViewControllerAnimated(viewController, animated); if (Trace.isEnabled()) { - Trace.write(`${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, Trace.categories.Navigation); + Trace.write( + `${this}.pushViewControllerAnimated(${viewController}, ${animated}); depth = ${navDepth}`, + Trace.categories.Navigation + ); } } - private pushViewControllerAnimated(viewController: UIViewController, animated: boolean, isModal: boolean) { + private pushViewControllerAnimated( + viewController: UIViewController, + animated: boolean, + isModal: boolean + ) { const transitionCoordinator = this._ios.controller.transitionCoordinator; if (!isModal && transitionCoordinator) { transitionCoordinator.animateAlongsideTransitionCompletion(null, () => { @@ -217,12 +250,17 @@ export class Frame extends FrameBase { navDepth = backstackEntry[NAV_DEPTH]; const controller = backstackEntry.resolvedPage.ios; - const animated = this._currentEntry ? this._getIsAnimatedNavigation(this._currentEntry.entry) : false; + const animated = this._currentEntry + ? this._getIsAnimatedNavigation(this._currentEntry.entry) + : false; this._updateActionBar(backstackEntry.resolvedPage); if (Trace.isEnabled()) { - Trace.write(`${this}.popToViewControllerAnimated(${controller}, ${animated}); depth = ${navDepth}`, Trace.categories.Navigation); + Trace.write( + `${this}.popToViewControllerAnimated(${controller}, ${animated}); depth = ${navDepth}`, + Trace.categories.Navigation + ); } this._ios.controller.popToViewControllerAnimated(controller, animated); @@ -252,7 +290,8 @@ export class Frame extends FrameBase { } if (this._ios.controller?.navigationBar) { - this._ios.controller.navigationBar.userInteractionEnabled = this.navigationQueueIsEmpty(); + this._ios.controller.navigationBar.userInteractionEnabled = + this.navigationQueueIsEmpty(); } if (needsPageLayout && page) { @@ -282,7 +321,9 @@ export class Frame extends FrameBase { if (page && page.actionBarHidden !== undefined) { newValue = !page.actionBarHidden; } else { - newValue = this.ios.controller.viewControllers.count > 1 || (page && page.actionBar && !page.actionBar._isEmpty()); + newValue = + this.ios.controller.viewControllers.count > 1 || + (page && page.actionBar && !page.actionBar._isEmpty()); } newValue = !!newValue; @@ -320,7 +361,12 @@ export class Frame extends FrameBase { this.setMeasuredDimension(widthAndState, heightAndState); } - public layoutNativeView(left: number, top: number, right: number, bottom: number): void { + public layoutNativeView( + left: number, + top: number, + right: number, + bottom: number + ): void { // } @@ -392,18 +438,28 @@ class TransitionDelegate extends NSObject { } @NativeClass -class UINavigationControllerAnimatedDelegate extends NSObject implements UINavigationControllerDelegate { +class UINavigationControllerAnimatedDelegate + extends NSObject + implements UINavigationControllerDelegate +{ public static ObjCProtocols = [UINavigationControllerDelegate]; owner: WeakRef; transition: PageTransition; static initWithOwner(owner: WeakRef) { - const delegate = UINavigationControllerAnimatedDelegate.new(); + const delegate = ( + UINavigationControllerAnimatedDelegate.new() + ); delegate.owner = owner; return delegate; } - navigationControllerAnimationControllerForOperationFromViewControllerToViewController(navigationController: UINavigationController, operation: number, fromVC: UIViewController, toVC: UIViewController): UIViewControllerAnimatedTransitioning { + navigationControllerAnimationControllerForOperationFromViewControllerToViewController( + navigationController: UINavigationController, + operation: number, + fromVC: UIViewController, + toVC: UIViewController + ): UIViewControllerAnimatedTransitioning { let viewController: UIViewController; switch (operation) { case UINavigationControllerOperation.Push: @@ -424,7 +480,12 @@ class UINavigationControllerAnimatedDelegate extends NSObject implements UINavig } if (Trace.isEnabled()) { - Trace.write(`UINavigationControllerImpl.navigationControllerAnimationControllerForOperationFromViewControllerToViewController(${operation}, ${fromVC}, ${toVC}), transition: ${JSON.stringify(navigationTransition)}`, Trace.categories.NativeLifecycle); + Trace.write( + `UINavigationControllerImpl.navigationControllerAnimationControllerForOperationFromViewControllerToViewController(${operation}, ${fromVC}, ${toVC}), transition: ${JSON.stringify( + navigationTransition + )}`, + Trace.categories.NativeLifecycle + ); } this.transition = navigationTransition.instance; @@ -434,7 +495,11 @@ class UINavigationControllerAnimatedDelegate extends NSObject implements UINavig const name = navigationTransition.name.toLowerCase(); if (name.indexOf('slide') === 0) { const direction = name.substring('slide'.length) || 'left'; //Extract the direction from the string - this.transition = new SlideTransition(direction, navigationTransition.duration, curve); + this.transition = new SlideTransition( + direction, + navigationTransition.duration, + curve + ); } else if (name === 'fade') { this.transition = new FadeTransition(navigationTransition.duration, curve); } @@ -442,12 +507,20 @@ class UINavigationControllerAnimatedDelegate extends NSObject implements UINavig } if (this.transition?.iosNavigatedController) { - return this.transition.iosNavigatedController(navigationController, operation, fromVC, toVC); + return this.transition.iosNavigatedController( + navigationController, + operation, + fromVC, + toVC + ); } return null; } - navigationControllerInteractionControllerForAnimationController(navigationController: UINavigationController, animationController: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning { + navigationControllerInteractionControllerForAnimationController( + navigationController: UINavigationController, + animationController: UIViewControllerAnimatedTransitioning + ): UIViewControllerInteractiveTransitioning { const owner = this.owner?.deref(); if (owner) { const state = SharedTransition.getState(owner.transitionId); @@ -496,8 +569,15 @@ class UINavigationControllerImpl extends UINavigationController { } } - private animateWithDuration(navigationTransition: NavigationTransition, nativeTransition: UIViewAnimationTransition, transitionType: string, baseCallback: Function): void { - const duration = navigationTransition.duration ? navigationTransition.duration / 1000 : CORE_ANIMATION_DEFAULTS.duration; + private animateWithDuration( + navigationTransition: NavigationTransition, + nativeTransition: UIViewAnimationTransition, + transitionType: string, + baseCallback: Function + ): void { + const duration = navigationTransition.duration + ? navigationTransition.duration / 1000 + : CORE_ANIMATION_DEFAULTS.duration; const curve = _getNativeCurve(navigationTransition); const transitionTraced = Trace.isCategorySet(Trace.categories.Transition); @@ -521,10 +601,18 @@ class UINavigationControllerImpl extends UINavigationController { } @profile - public pushViewControllerAnimated(viewController: UIViewController, animated: boolean): void { + public pushViewControllerAnimated( + viewController: UIViewController, + animated: boolean + ): void { const navigationTransition = viewController[TRANSITION]; if (Trace.isEnabled()) { - Trace.write(`UINavigationControllerImpl.pushViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, Trace.categories.NativeLifecycle); + Trace.write( + `UINavigationControllerImpl.pushViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify( + navigationTransition + )}`, + Trace.categories.NativeLifecycle + ); } const nativeTransition = _getNativeTransition(navigationTransition, true); @@ -540,12 +628,20 @@ class UINavigationControllerImpl extends UINavigationController { } @profile - public setViewControllersAnimated(viewControllers: NSArray, animated: boolean): void { + public setViewControllersAnimated( + viewControllers: NSArray, + animated: boolean + ): void { const viewController = viewControllers.lastObject; const navigationTransition = viewController[TRANSITION]; if (Trace.isEnabled()) { - Trace.write(`UINavigationControllerImpl.setViewControllersAnimated(${viewControllers}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, Trace.categories.NativeLifecycle); + Trace.write( + `UINavigationControllerImpl.setViewControllersAnimated(${viewControllers}, ${animated}); transition: ${JSON.stringify( + navigationTransition + )}`, + Trace.categories.NativeLifecycle + ); } const nativeTransition = _getNativeTransition(navigationTransition, true); @@ -564,7 +660,12 @@ class UINavigationControllerImpl extends UINavigationController { const lastViewController = this.viewControllers.lastObject; const navigationTransition = lastViewController[TRANSITION]; if (Trace.isEnabled()) { - Trace.write(`UINavigationControllerImpl.popViewControllerAnimated(${animated}); transition: ${JSON.stringify(navigationTransition)}`, Trace.categories.NativeLifecycle); + Trace.write( + `UINavigationControllerImpl.popViewControllerAnimated(${animated}); transition: ${JSON.stringify( + navigationTransition + )}`, + Trace.categories.NativeLifecycle + ); } if (navigationTransition && navigationTransition.name === NON_ANIMATED_TRANSITION) { @@ -584,11 +685,19 @@ class UINavigationControllerImpl extends UINavigationController { return null; } - public popToViewControllerAnimated(viewController: UIViewController, animated: boolean): NSArray { + public popToViewControllerAnimated( + viewController: UIViewController, + animated: boolean + ): NSArray { const lastViewController = this.viewControllers.lastObject; const navigationTransition = lastViewController[TRANSITION]; if (Trace.isEnabled()) { - Trace.write(`UINavigationControllerImpl.popToViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, Trace.categories.NativeLifecycle); + Trace.write( + `UINavigationControllerImpl.popToViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify( + navigationTransition + )}`, + Trace.categories.NativeLifecycle + ); } if (navigationTransition && navigationTransition.name === NON_ANIMATED_TRANSITION) { @@ -614,7 +723,13 @@ class UINavigationControllerImpl extends UINavigationController { if (majorVersion >= 13) { const owner = this._owner?.deref?.(); - if (owner && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection(previousTraitCollection)) { + if ( + owner && + this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection && + this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection( + previousTraitCollection + ) + ) { owner.notify({ eventName: IOSHelper.traitCollectionColorAppearanceChangedEvent, object: owner, @@ -624,7 +739,10 @@ class UINavigationControllerImpl extends UINavigationController { } } -function _getTransitionId(nativeTransition: UIViewAnimationTransition, transitionType: string): string { +function _getTransitionId( + nativeTransition: UIViewAnimationTransition, + transitionType: string +): string { let name; switch (nativeTransition) { case UIViewAnimationTransition.CurlDown: @@ -647,19 +765,30 @@ function _getTransitionId(nativeTransition: UIViewAnimationTransition, transitio return `${name} ${transitionType}`; } -function _getNativeTransition(navigationTransition: NavigationTransition, push: boolean): UIViewAnimationTransition { +function _getNativeTransition( + navigationTransition: NavigationTransition, + push: boolean +): UIViewAnimationTransition { if (navigationTransition && navigationTransition.name) { switch (navigationTransition.name.toLowerCase()) { case 'flip': case 'flipright': - return push ? UIViewAnimationTransition.FlipFromRight : UIViewAnimationTransition.FlipFromLeft; + return push + ? UIViewAnimationTransition.FlipFromRight + : UIViewAnimationTransition.FlipFromLeft; case 'flipleft': - return push ? UIViewAnimationTransition.FlipFromLeft : UIViewAnimationTransition.FlipFromRight; + return push + ? UIViewAnimationTransition.FlipFromLeft + : UIViewAnimationTransition.FlipFromRight; case 'curl': case 'curlup': - return push ? UIViewAnimationTransition.CurlUp : UIViewAnimationTransition.CurlDown; + return push + ? UIViewAnimationTransition.CurlUp + : UIViewAnimationTransition.CurlDown; case 'curldown': - return push ? UIViewAnimationTransition.CurlDown : UIViewAnimationTransition.CurlUp; + return push + ? UIViewAnimationTransition.CurlDown + : UIViewAnimationTransition.CurlUp; } } @@ -671,35 +800,50 @@ export function _getNativeCurve(transition: NavigationTransition): UIViewAnimati switch (transition.curve) { case 'easeIn': if (Trace.isEnabled()) { - Trace.write('Transition curve resolved to UIViewAnimationCurve.EaseIn.', Trace.categories.Transition); + Trace.write( + 'Transition curve resolved to UIViewAnimationCurve.EaseIn.', + Trace.categories.Transition + ); } return UIViewAnimationCurve.EaseIn; case 'easeOut': if (Trace.isEnabled()) { - Trace.write('Transition curve resolved to UIViewAnimationCurve.EaseOut.', Trace.categories.Transition); + Trace.write( + 'Transition curve resolved to UIViewAnimationCurve.EaseOut.', + Trace.categories.Transition + ); } return UIViewAnimationCurve.EaseOut; case 'easeInOut': if (Trace.isEnabled()) { - Trace.write('Transition curve resolved to UIViewAnimationCurve.EaseInOut.', Trace.categories.Transition); + Trace.write( + 'Transition curve resolved to UIViewAnimationCurve.EaseInOut.', + Trace.categories.Transition + ); } return UIViewAnimationCurve.EaseInOut; case 'linear': if (Trace.isEnabled()) { - Trace.write('Transition curve resolved to UIViewAnimationCurve.Linear.', Trace.categories.Transition); + Trace.write( + 'Transition curve resolved to UIViewAnimationCurve.Linear.', + Trace.categories.Transition + ); } return UIViewAnimationCurve.Linear; default: if (Trace.isEnabled()) { - Trace.write('Transition curve resolved to original: ' + transition.curve, Trace.categories.Transition); + Trace.write( + 'Transition curve resolved to original: ' + transition.curve, + Trace.categories.Transition + ); } return transition.curve; @@ -737,7 +881,10 @@ class iOSFrame implements iOSFrameDefinition { public set showNavigationBar(value: boolean) { this._showNavigationBar = value; if (this._controller) { - this._controller.setNavigationBarHiddenAnimated(!value, !this._disableNavBarAnimation); + this._controller.setNavigationBarHiddenAnimated( + !value, + !this._disableNavBarAnimation + ); } } diff --git a/packages/core/utils/android/index.ts b/packages/core/utils/android/index.ts index 8ad9f8f23..e5352a95e 100644 --- a/packages/core/utils/android/index.ts +++ b/packages/core/utils/android/index.ts @@ -33,7 +33,7 @@ export function getResources() { return contextResources; } -function getPackageName() { +export function getPackageName() { if (!packageName) { packageName = getApplicationContext().getPackageName(); } diff --git a/packages/core/utils/mainthread-helper.android.ts b/packages/core/utils/mainthread-helper.android.ts index 8f47797a9..0017c6999 100644 --- a/packages/core/utils/mainthread-helper.android.ts +++ b/packages/core/utils/mainthread-helper.android.ts @@ -1,4 +1,4 @@ -import { ad } from './native-helper'; +import { android as androidHelper } from './native-helper'; export function dispatchToMainThread(func: () => void) { const runOnMainThread = (global as any).__runOnMainThread; @@ -20,7 +20,7 @@ export function isMainThread(): boolean { } export function dispatchToUIThread(func: () => void) { - const activity: androidx.appcompat.app.AppCompatActivity = ad.getCurrentActivity(); + const activity = androidHelper.getCurrentActivity(); if (activity && func) { activity.runOnUiThread( new java.lang.Runnable({