refactor: additional cleanup and code reuse

This commit is contained in:
Igor Randjelovic
2023-05-12 16:51:29 +02:00
parent 5b4624a308
commit f7d5a8e8a6
9 changed files with 544 additions and 353 deletions

View File

@ -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((<any>args.error).nativeException || (<any>args.error).nativeError);
console.log((<any>args.error).stackTrace || (<any>args.error).stack);
console.log('NativeScriptError:', args.error);
console.log((<any>args.error).nativeException ?? (<any>args.error).nativeError);
console.log((<any>args.error).stackTrace ?? (<any>args.error).stack);
});
Application.on(Application.discardedErrorEvent, function (args: DiscardedErrorEventData) {
console.log('[Discarded] NativeScriptError: ' + args.error);
console.log((<any>args.error).nativeException || (<any>args.error).nativeError);
console.log((<any>args.error).stackTrace || (<any>args.error).stack);
console.log('[Discarded] NativeScriptError:', args.error);
console.log((<any>args.error).nativeException ?? (<any>args.error).nativeError);
console.log((<any>args.error).stackTrace ?? (<any>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
);
}
);

View File

@ -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 ||
((<any>rootView).currentPage && (<any>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
* <key>CADisableMinimumFrameDurationOnPhone</key>
* <true/>
* ```
* @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(<LoadAppCSSEventData>{
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(<CssChangedEventData>{
eventName: 'cssChanged',
object: this, // <any>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(<SystemAppearanceChangedEventData>{
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 = <Array<View>>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(<ApplicationEventData>{
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(<ApplicationEventData>{
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;

View File

@ -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;
}

View File

@ -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: (

View File

@ -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(<ApplicationEventData>{
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(<LoadAppCSSEventData>{
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(<ApplicationEventData>{
eventName: this.resumeEvent,
object: this,
ios: this.ios,
});
this.notify(<ApplicationEventData>{
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(<ApplicationEventData>{
eventName: this.suspendEvent,
object: this,
ios: this.ios,
});
this.notify(<ApplicationEventData>{
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) {

View File

@ -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 ((<any>activity).isNativeScriptActivity) {
Application.setSuspended(false);
const args = <ApplicationEventData>{
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, <any>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(<LoadAppCSSEventData>{
eventName: 'loadAppCss',
object: Application,
android: Application.android,
cssFile: Application.getCssFileName(),
});
return launchArgs.root;
}
);
export function setActivityCallbacks(
activity: androidx.appcompat.app.AppCompatActivity
): void {

View File

@ -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 = <UINavigationControllerDelegate>UINavigationControllerAnimatedDelegate.initWithOwner(new WeakRef(this));
this._animatedDelegate = <UINavigationControllerDelegate>(
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<UIViewController>().initWithArray(this._ios.controller.viewControllers);
const newControllers = NSMutableArray.alloc<UIViewController>().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<Frame>;
transition: PageTransition;
static initWithOwner(owner: WeakRef<Frame>) {
const delegate = <UINavigationControllerAnimatedDelegate>UINavigationControllerAnimatedDelegate.new();
const delegate = <UINavigationControllerAnimatedDelegate>(
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 = <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<any>, animated: boolean): void {
public setViewControllersAnimated(
viewControllers: NSArray<any>,
animated: boolean
): void {
const viewController = viewControllers.lastObject;
const navigationTransition = <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 = <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<UIViewController> {
public popToViewControllerAnimated(
viewController: UIViewController,
animated: boolean
): NSArray<UIViewController> {
const lastViewController = this.viewControllers.lastObject;
const navigationTransition = <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
);
}
}

View File

@ -33,7 +33,7 @@ export function getResources() {
return contextResources;
}
function getPackageName() {
export function getPackageName() {
if (!packageName) {
packageName = getApplicationContext().getPackageName();
}

View File

@ -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({