mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
refactor: move ios/android utils into separate modules
This commit is contained in:
@@ -3,7 +3,7 @@ import { getPageStartDefaultsForType, getRectFromProps, getSpringFromProps, Shar
|
||||
import { isNumber } from '../../utils/types';
|
||||
import { Screen } from '../../platform';
|
||||
import { CORE_ANIMATION_DEFAULTS } from '../../utils/common';
|
||||
import { iOSNativeHelper } from '../../utils/native-helper';
|
||||
import { ios as iOSUtils } from '../../utils/native-helper';
|
||||
|
||||
interface PlatformTransitionInteractiveState extends TransitionInteractiveState {
|
||||
transitionContext?: UIViewControllerContextTransitioning;
|
||||
@@ -81,7 +81,7 @@ export class SharedTransitionHelper {
|
||||
// in case the image is loaded async, we need to update the snapshot when it changes
|
||||
// todo: remove listener on transition end
|
||||
presentedView.on('imageSourceChange', () => {
|
||||
snapshot.image = iOSNativeHelper.snapshotView(presentedSharedElement, Screen.mainScreen.scale);
|
||||
snapshot.image = iOSUtils.snapshotView(presentedSharedElement, Screen.mainScreen.scale);
|
||||
snapshot.tintColor = presentedSharedElement.tintColor;
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@ export class SharedTransitionHelper {
|
||||
snapshot.contentMode = presentedSharedElement.contentMode;
|
||||
}
|
||||
|
||||
iOSNativeHelper.copyLayerProperties(snapshot, presentingSharedElement, pageEndProps?.propertiesToMatch);
|
||||
iOSUtils.copyLayerProperties(snapshot, presentingSharedElement, pageEndProps?.propertiesToMatch as any);
|
||||
snapshot.clipsToBounds = true;
|
||||
// console.log('---> snapshot: ', snapshot);
|
||||
|
||||
@@ -97,7 +97,7 @@ export class SharedTransitionHelper {
|
||||
const endFrame = presentedSharedElement.convertRectToView(presentedSharedElement.bounds, transitionContext.containerView);
|
||||
snapshot.frame = startFrame;
|
||||
if (SharedTransition.DEBUG) {
|
||||
console.log('---> ', presentingView.sharedTransitionTag, ' frame:', iOSNativeHelper.printCGRect(snapshot.frame));
|
||||
console.log('---> ', presentingView.sharedTransitionTag, ' frame:', iOSUtils.printCGRect(snapshot.frame));
|
||||
}
|
||||
|
||||
transition.sharedElements.presenting.push({
|
||||
@@ -151,11 +151,11 @@ export class SharedTransitionHelper {
|
||||
await pageEndProps?.callback(independentView, 'present');
|
||||
}
|
||||
|
||||
let snapshot: UIImageView;
|
||||
// let snapshot: UIImageView;
|
||||
// if (isPresented) {
|
||||
// snapshot = UIImageView.alloc().init();
|
||||
// } else {
|
||||
snapshot = UIImageView.alloc().initWithImage(iOSNativeHelper.snapshotView(independentSharedElement, Screen.mainScreen.scale));
|
||||
const snapshot = UIImageView.alloc().initWithImage(iOSUtils.snapshotView(independentSharedElement, Screen.mainScreen.scale));
|
||||
// }
|
||||
|
||||
if (independentSharedElement instanceof UIImageView) {
|
||||
@@ -184,7 +184,7 @@ export class SharedTransitionHelper {
|
||||
snapshot.frame = startFrame; //startFrameAdjusted;
|
||||
// }
|
||||
if (SharedTransition.DEBUG) {
|
||||
console.log('---> ', independentView.sharedTransitionTag, ' frame:', iOSNativeHelper.printCGRect(snapshot.frame));
|
||||
console.log('---> ', independentView.sharedTransitionTag, ' frame:', iOSUtils.printCGRect(snapshot.frame));
|
||||
}
|
||||
|
||||
const endFrameRect = getRectFromProps(pageEndProps);
|
||||
@@ -289,18 +289,18 @@ export class SharedTransitionHelper {
|
||||
presentingMatch.snapshot.frame = correctedEndFrame;
|
||||
|
||||
// apply view and layer properties to the snapshot view to match the source/presented view
|
||||
iOSNativeHelper.copyLayerProperties(presentingMatch.snapshot, presented.view.ios, presented.propertiesToMatch);
|
||||
iOSUtils.copyLayerProperties(presentingMatch.snapshot, presented.view.ios, presented.propertiesToMatch as any);
|
||||
// create a snapshot of the presented view
|
||||
presentingMatch.snapshot.image = iOSNativeHelper.snapshotView(presented.view.ios, Screen.mainScreen.scale);
|
||||
presentingMatch.snapshot.image = iOSUtils.snapshotView(presented.view.ios, Screen.mainScreen.scale);
|
||||
// apply correct alpha
|
||||
presentingMatch.snapshot.alpha = presentingMatch.endOpacity;
|
||||
|
||||
if (SharedTransition.DEBUG) {
|
||||
console.log(`---> ${presentingMatch.view.sharedTransitionTag} animate to: `, iOSNativeHelper.printCGRect(correctedEndFrame));
|
||||
console.log(`---> ${presentingMatch.view.sharedTransitionTag} animate to: `, iOSUtils.printCGRect(correctedEndFrame));
|
||||
}
|
||||
}
|
||||
for (const independent of transition.sharedElements.independent) {
|
||||
let endFrame: CGRect = independent.endFrame;
|
||||
const endFrame: CGRect = independent.endFrame;
|
||||
// if (independent.isPresented) {
|
||||
// const updatedEndFrame = independent.view.ios.convertRectToView(independent.view.ios.bounds, transitionContext.containerView);
|
||||
// endFrame = CGRectMake(updatedEndFrame.origin.x, updatedEndFrame.origin.y, independent.endFrame.size.width, independent.endFrame.size.height);
|
||||
@@ -313,7 +313,7 @@ export class SharedTransitionHelper {
|
||||
independent.snapshot.alpha = independent.endOpacity;
|
||||
|
||||
if (SharedTransition.DEBUG) {
|
||||
console.log(`---> ${independent.view.sharedTransitionTag} animate to: `, iOSNativeHelper.printCGRect(independent.endFrame));
|
||||
console.log(`---> ${independent.view.sharedTransitionTag} animate to: `, iOSUtils.printCGRect(independent.endFrame));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -332,7 +332,7 @@ export class SharedTransitionHelper {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
iOSNativeHelper.animateWithSpring({
|
||||
iOSUtils.animateWithSpring({
|
||||
...getSpringFromProps(pageEnd?.spring),
|
||||
animations: () => {
|
||||
animateProperties();
|
||||
@@ -409,7 +409,7 @@ export class SharedTransitionHelper {
|
||||
}
|
||||
|
||||
// take a new snapshot
|
||||
data.snapshot.image = iOSNativeHelper.snapshotView(view, Screen.mainScreen.scale);
|
||||
data.snapshot.image = iOSUtils.snapshotView(view, Screen.mainScreen.scale);
|
||||
|
||||
// find the currently visible view with the same sharedTransitionTag
|
||||
const fromView = transition.sharedElements.presented.find((p) => p.view.sharedTransitionTag === data.view.sharedTransitionTag)?.view;
|
||||
@@ -458,12 +458,12 @@ export class SharedTransitionHelper {
|
||||
transition.presented.view.frame = CGRectMake(endFrame.x, endFrame.y, endFrame.width, endFrame.height);
|
||||
|
||||
for (const presenting of transition.sharedElements.presenting) {
|
||||
iOSNativeHelper.copyLayerProperties(presenting.snapshot, presenting.view.ios, presenting.propertiesToMatch);
|
||||
iOSUtils.copyLayerProperties(presenting.snapshot, presenting.view.ios, presenting.propertiesToMatch as any);
|
||||
presenting.snapshot.frame = presenting.startFrame;
|
||||
presenting.snapshot.alpha = presenting.startOpacity;
|
||||
|
||||
if (SharedTransition.DEBUG) {
|
||||
console.log(`---> ${presenting.view.sharedTransitionTag} animate to: `, iOSNativeHelper.printCGRect(presenting.snapshot.frame));
|
||||
console.log(`---> ${presenting.view.sharedTransitionTag} animate to: `, iOSUtils.printCGRect(presenting.snapshot.frame));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,7 +476,7 @@ export class SharedTransitionHelper {
|
||||
}
|
||||
|
||||
if (SharedTransition.DEBUG) {
|
||||
console.log(`---> ${independent.view.sharedTransitionTag} animate to: `, iOSNativeHelper.printCGRect(independent.snapshot.frame));
|
||||
console.log(`---> ${independent.view.sharedTransitionTag} animate to: `, iOSUtils.printCGRect(independent.snapshot.frame));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -495,7 +495,7 @@ export class SharedTransitionHelper {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
iOSNativeHelper.animateWithSpring({
|
||||
iOSUtils.animateWithSpring({
|
||||
...getSpringFromProps(pageReturn?.spring),
|
||||
animations: () => {
|
||||
animateProperties();
|
||||
@@ -542,7 +542,7 @@ export class SharedTransitionHelper {
|
||||
interactiveState.propertyAnimator = UIViewPropertyAnimator.alloc().initWithDurationDampingRatioAnimations(1, 1, () => {
|
||||
for (const p of state.instance.sharedElements.presenting) {
|
||||
p.snapshot.frame = p.startFrame;
|
||||
iOSNativeHelper.copyLayerProperties(p.snapshot, p.view.ios, p.propertiesToMatch);
|
||||
iOSUtils.copyLayerProperties(p.snapshot, p.view.ios, p.propertiesToMatch as any);
|
||||
|
||||
p.snapshot.alpha = 1;
|
||||
}
|
||||
|
||||
171
packages/core/utils/android/index.ts
Normal file
171
packages/core/utils/android/index.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { getNativeApplication, android as androidApp } from '../../application';
|
||||
import { Trace } from '../../trace';
|
||||
|
||||
let application: android.app.Application;
|
||||
let applicationContext: android.content.Context;
|
||||
let contextResources: android.content.res.Resources;
|
||||
let packageName: string;
|
||||
|
||||
export function getApplicationContext() {
|
||||
if (!applicationContext) {
|
||||
applicationContext = getApplication().getApplicationContext();
|
||||
}
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
export function getCurrentActivity() {
|
||||
if (!androidApp) {
|
||||
return null;
|
||||
}
|
||||
return androidApp.foregroundActivity || androidApp.startActivity;
|
||||
}
|
||||
export function getApplication() {
|
||||
if (!application) {
|
||||
application = <android.app.Application>getNativeApplication();
|
||||
}
|
||||
|
||||
return application;
|
||||
}
|
||||
export function getResources() {
|
||||
if (!contextResources) {
|
||||
contextResources = getApplication().getResources();
|
||||
}
|
||||
|
||||
return contextResources;
|
||||
}
|
||||
function getPackageName() {
|
||||
if (!packageName) {
|
||||
packageName = getApplicationContext().getPackageName();
|
||||
}
|
||||
|
||||
return packageName;
|
||||
}
|
||||
|
||||
let inputMethodManager: android.view.inputmethod.InputMethodManager;
|
||||
export function getInputMethodManager(): android.view.inputmethod.InputMethodManager {
|
||||
if (!inputMethodManager) {
|
||||
inputMethodManager = <android.view.inputmethod.InputMethodManager>getApplicationContext().getSystemService(android.content.Context.INPUT_METHOD_SERVICE);
|
||||
}
|
||||
|
||||
return inputMethodManager;
|
||||
}
|
||||
|
||||
export function showSoftInput(nativeView: android.view.View): void {
|
||||
const inputManager = getInputMethodManager();
|
||||
if (inputManager && nativeView instanceof android.view.View) {
|
||||
inputManager.showSoftInput(nativeView, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
|
||||
export function dismissSoftInput(nativeView?: android.view.View): void {
|
||||
const inputManager = getInputMethodManager();
|
||||
let windowToken: android.os.IBinder;
|
||||
|
||||
if (nativeView instanceof android.view.View) {
|
||||
if (!nativeView.hasFocus()) {
|
||||
return;
|
||||
}
|
||||
windowToken = nativeView.getWindowToken();
|
||||
} else if (getCurrentActivity() instanceof androidx.appcompat.app.AppCompatActivity) {
|
||||
const decorView = getCurrentActivity().getWindow().getDecorView();
|
||||
if (decorView) {
|
||||
windowToken = decorView.getWindowToken();
|
||||
decorView.requestFocus();
|
||||
} else {
|
||||
windowToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputManager && windowToken) {
|
||||
inputManager.hideSoftInputFromWindow(windowToken, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export namespace collections {
|
||||
export function stringArrayToStringSet(str: string[]): java.util.HashSet<string> {
|
||||
const hashSet = new java.util.HashSet<string>();
|
||||
if (str !== undefined) {
|
||||
for (const element in str) {
|
||||
hashSet.add('' + str[element]);
|
||||
}
|
||||
}
|
||||
|
||||
return hashSet;
|
||||
}
|
||||
|
||||
export function stringSetToStringArray(stringSet: any): string[] {
|
||||
const arr = [];
|
||||
if (stringSet !== undefined) {
|
||||
const it = stringSet.iterator();
|
||||
while (it.hasNext()) {
|
||||
const element = '' + it.next();
|
||||
arr.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace resources {
|
||||
let attr;
|
||||
const attrCache = new Map<string, number>();
|
||||
|
||||
export function getDrawableId(name) {
|
||||
return getId(':drawable/' + name);
|
||||
}
|
||||
|
||||
export function getStringId(name) {
|
||||
return getId(':string/' + name);
|
||||
}
|
||||
|
||||
export function getId(name: string): number {
|
||||
const resources = getResources();
|
||||
const packageName = getPackageName();
|
||||
const uri = packageName + name;
|
||||
|
||||
return resources.getIdentifier(uri, null, null);
|
||||
}
|
||||
export function getResource(name: string, type?: string): number {
|
||||
return getResources().getIdentifier(name, type, getPackageName());
|
||||
}
|
||||
export function getPalleteColor(name: string, context: android.content.Context): number {
|
||||
return getPaletteColor(name, context);
|
||||
}
|
||||
export function getPaletteColor(name: string, context: android.content.Context): number {
|
||||
if (attrCache.has(name)) {
|
||||
return attrCache.get(name);
|
||||
}
|
||||
|
||||
let result = 0;
|
||||
try {
|
||||
if (!attr) {
|
||||
attr = java.lang.Class.forName('androidx.appcompat.R$attr');
|
||||
}
|
||||
|
||||
let colorID = 0;
|
||||
const field = attr.getField(name);
|
||||
if (field) {
|
||||
colorID = field.getInt(null);
|
||||
}
|
||||
|
||||
if (colorID) {
|
||||
const typedValue = new android.util.TypedValue();
|
||||
context.getTheme().resolveAttribute(colorID, typedValue, true);
|
||||
result = typedValue.data;
|
||||
}
|
||||
} catch (ex) {
|
||||
Trace.write('Cannot get pallete color: ' + name, Trace.categories.Error, Trace.messageType.error);
|
||||
}
|
||||
|
||||
attrCache.set(name, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function isRealDevice(): boolean {
|
||||
const fingerprint = android.os.Build.FINGERPRINT;
|
||||
|
||||
return fingerprint != null && (fingerprint.indexOf('vbox') > -1 || fingerprint.indexOf('generic') > -1);
|
||||
}
|
||||
329
packages/core/utils/ios/index.ts
Normal file
329
packages/core/utils/ios/index.ts
Normal file
@@ -0,0 +1,329 @@
|
||||
import { Color } from '../../color';
|
||||
import { Trace } from '../../trace';
|
||||
import { CORE_ANIMATION_DEFAULTS, getDurationWithDampingFromSpring } from '../common';
|
||||
|
||||
declare let UIImagePickerControllerSourceType: any;
|
||||
|
||||
const radToDeg = Math.PI / 180;
|
||||
|
||||
function isOrientationLandscape(orientation: number) {
|
||||
return orientation === UIDeviceOrientation.LandscapeLeft /* 3 */ || orientation === UIDeviceOrientation.LandscapeRight /* 4 */;
|
||||
}
|
||||
|
||||
function openFileAtRootModule(filePath: string): boolean {
|
||||
try {
|
||||
const appPath = getCurrentAppPath();
|
||||
const path = isRealDevice() ? filePath.replace('~', appPath) : filePath;
|
||||
|
||||
const controller = UIDocumentInteractionController.interactionControllerWithURL(NSURL.fileURLWithPath(path));
|
||||
controller.delegate = createUIDocumentInteractionControllerDelegate();
|
||||
|
||||
return controller.presentPreviewAnimated(true);
|
||||
} catch (e) {
|
||||
Trace.write('Error in openFile', Trace.categories.Error, Trace.messageType.error);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// TODO: remove for NativeScript 9.0
|
||||
export function getter<T>(_this: any, property: T | { (): T }): T {
|
||||
console.log('utils.ios.getter() is deprecated; use the respective native property instead');
|
||||
if (typeof property === 'function') {
|
||||
return (<{ (): T }>property).call(_this);
|
||||
} else {
|
||||
return <T>property;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace collections {
|
||||
export function jsArrayToNSArray<T>(str: T[]): NSArray<T> {
|
||||
return NSArray.arrayWithArray(str);
|
||||
}
|
||||
|
||||
export function nsArrayToJSArray<T>(a: NSArray<T>): Array<T> {
|
||||
const arr = [];
|
||||
if (a !== undefined) {
|
||||
const count = a.count;
|
||||
for (let i = 0; i < count; i++) {
|
||||
arr.push(a.objectAtIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
export function getRootViewController(): UIViewController {
|
||||
const win = getWindow();
|
||||
let vc = win && win.rootViewController;
|
||||
while (vc && vc.presentedViewController) {
|
||||
vc = vc.presentedViewController;
|
||||
}
|
||||
return vc;
|
||||
}
|
||||
|
||||
export function getWindow(): UIWindow {
|
||||
const app = UIApplication.sharedApplication;
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
return app.keyWindow || (app.windows && app.windows.count > 0 && app.windows.objectAtIndex(0));
|
||||
}
|
||||
|
||||
export function setWindowBackgroundColor(value: string) {
|
||||
const win = getWindow();
|
||||
if (win) {
|
||||
const bgColor = new Color(value);
|
||||
win.backgroundColor = bgColor.ios;
|
||||
const rootVc = getRootViewController();
|
||||
if (rootVc?.view) {
|
||||
rootVc.view.backgroundColor = bgColor.ios;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isLandscape(): boolean {
|
||||
console.log('utils.ios.isLandscape() is deprecated; use application.orientation instead');
|
||||
|
||||
const deviceOrientation = UIDevice.currentDevice.orientation;
|
||||
const statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
|
||||
|
||||
const isDeviceOrientationLandscape = isOrientationLandscape(deviceOrientation);
|
||||
const isStatusBarOrientationLandscape = isOrientationLandscape(statusBarOrientation);
|
||||
|
||||
return isDeviceOrientationLandscape || isStatusBarOrientationLandscape;
|
||||
}
|
||||
|
||||
export const MajorVersion = NSString.stringWithString(UIDevice.currentDevice.systemVersion).intValue;
|
||||
|
||||
export function openFile(filePath: string): boolean {
|
||||
console.log('utils.ios.openFile() is deprecated; use utils.openFile() instead');
|
||||
|
||||
return openFileAtRootModule(filePath);
|
||||
}
|
||||
|
||||
export function getCurrentAppPath(): string {
|
||||
const currentDir = __dirname;
|
||||
const tnsModulesIndex = currentDir.indexOf('/tns_modules');
|
||||
|
||||
// Module not hosted in ~/tns_modules when bundled. Use current dir.
|
||||
let appPath = currentDir;
|
||||
if (tnsModulesIndex !== -1) {
|
||||
// Strip part after tns_modules to obtain app root
|
||||
appPath = currentDir.substring(0, tnsModulesIndex);
|
||||
}
|
||||
|
||||
return appPath;
|
||||
}
|
||||
|
||||
export function joinPaths(...paths: string[]): string {
|
||||
if (!paths || paths.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return NSString.stringWithString(NSString.pathWithComponents(<any>paths)).stringByStandardizingPath;
|
||||
}
|
||||
|
||||
export function getVisibleViewController(rootViewController: UIViewController): UIViewController {
|
||||
let viewController = rootViewController;
|
||||
|
||||
while (viewController && viewController.presentedViewController) {
|
||||
viewController = viewController.presentedViewController;
|
||||
}
|
||||
return viewController;
|
||||
}
|
||||
|
||||
export function applyRotateTransform(transform: CATransform3D, x: number, y: number, z: number): CATransform3D {
|
||||
if (x) {
|
||||
transform = CATransform3DRotate(transform, x * radToDeg, 1, 0, 0);
|
||||
}
|
||||
|
||||
if (y) {
|
||||
transform = CATransform3DRotate(transform, y * radToDeg, 0, 1, 0);
|
||||
}
|
||||
|
||||
if (z) {
|
||||
transform = CATransform3DRotate(transform, z * radToDeg, 0, 0, 1);
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
export function getShadowLayer(nativeView: UIView, name: string = 'ns-shadow-layer', create: boolean = true): CALayer {
|
||||
return nativeView.layer;
|
||||
|
||||
console.log(`--- ${create ? 'CREATE' : 'READ'}`);
|
||||
|
||||
/**
|
||||
* UIView
|
||||
* -> Shadow
|
||||
*
|
||||
*
|
||||
* UIView
|
||||
* -> UIView
|
||||
* -> Shadow
|
||||
*/
|
||||
|
||||
if (!nativeView) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!nativeView.layer) {
|
||||
// should never hit this?
|
||||
console.log('- no layer! -');
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the nativeView's layer is the shadow layer?
|
||||
if (nativeView.layer.name === name) {
|
||||
console.log('- found shadow layer - reusing.');
|
||||
return nativeView.layer;
|
||||
}
|
||||
|
||||
console.log('>> layer :', nativeView.layer);
|
||||
if (nativeView.layer.sublayers?.count) {
|
||||
const count = nativeView.layer.sublayers.count;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const subLayer = nativeView.layer.sublayers.objectAtIndex(i);
|
||||
|
||||
console.log(`>> subLayer ${i + 1}/${count} :`, subLayer);
|
||||
console.log(`>> subLayer ${i + 1}/${count} name :`, subLayer.name);
|
||||
|
||||
if (subLayer.name === name) {
|
||||
console.log('- found shadow sublayer - reusing.');
|
||||
return subLayer;
|
||||
}
|
||||
}
|
||||
// if (nativeView instanceof UITextView) {
|
||||
// return nativeView.layer.sublayers.objectAtIndex(1);
|
||||
// } else {
|
||||
// return nativeView.layer.sublayers.objectAtIndex(nativeView.layer.sublayers.count - 1);
|
||||
// }
|
||||
}
|
||||
// else {
|
||||
// layer = nativeView.layer;
|
||||
// }
|
||||
|
||||
// we're not interested in creating a new layer
|
||||
if (!create) {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`- adding a new layer for - ${name}`);
|
||||
|
||||
const viewLayer = nativeView.layer;
|
||||
const newLayer = CALayer.layer();
|
||||
|
||||
newLayer.name = name;
|
||||
newLayer.zPosition = 0.0;
|
||||
// nativeView.layer.insertSublayerBelow(newLayer, nativeView.layer)
|
||||
// newLayer.insertSublayerAtIndex(nativeView.layer, 0)
|
||||
// nativeView.layer.zPosition = 1.0;
|
||||
// nativeView.layer.addSublayer(newLayer);
|
||||
|
||||
// nativeView.layer = CALayer.layer()
|
||||
|
||||
nativeView.layer.insertSublayerAtIndex(newLayer, 0);
|
||||
// nativeView.layer.insertSublayerAtIndex(viewLayer, 1)
|
||||
|
||||
// nativeView.layer.replaceSublayerWith(newLayer, nativeView.layer);
|
||||
|
||||
return newLayer;
|
||||
}
|
||||
|
||||
export function createUIDocumentInteractionControllerDelegate(): NSObject {
|
||||
@NativeClass
|
||||
class UIDocumentInteractionControllerDelegateImpl extends NSObject implements UIDocumentInteractionControllerDelegate {
|
||||
public static ObjCProtocols = [UIDocumentInteractionControllerDelegate];
|
||||
|
||||
public getViewController(): UIViewController {
|
||||
const app = UIApplication.sharedApplication;
|
||||
|
||||
return app.keyWindow.rootViewController;
|
||||
}
|
||||
|
||||
public documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) {
|
||||
return this.getViewController();
|
||||
}
|
||||
|
||||
public documentInteractionControllerViewForPreview(controller: UIDocumentInteractionController) {
|
||||
return this.getViewController().view;
|
||||
}
|
||||
|
||||
public documentInteractionControllerRectForPreview(controller: UIDocumentInteractionController): CGRect {
|
||||
return this.getViewController().view.frame;
|
||||
}
|
||||
}
|
||||
return new UIDocumentInteractionControllerDelegateImpl();
|
||||
}
|
||||
|
||||
export function isRealDevice() {
|
||||
try {
|
||||
// https://stackoverflow.com/a/5093092/4936697
|
||||
const sourceType = UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypeCamera;
|
||||
const mediaTypes = UIImagePickerController.availableMediaTypesForSourceType(sourceType);
|
||||
|
||||
return !!mediaTypes;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function printCGRect(rect: CGRect) {
|
||||
if (rect) {
|
||||
return `CGRect(${rect.origin.x} ${rect.origin.y} ${rect.size.width} ${rect.size.height})`;
|
||||
}
|
||||
}
|
||||
|
||||
export function snapshotView(view: UIView, scale: number): UIImage {
|
||||
if (view instanceof UIImageView) {
|
||||
return view.image;
|
||||
}
|
||||
// console.log('snapshotView view.frame:', printRect(view.frame));
|
||||
const originalOpacity = view.layer.opacity;
|
||||
view.layer.opacity = originalOpacity > 0 ? originalOpacity : 1;
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(view.frame.size.width, view.frame.size.height), false, scale);
|
||||
view.layer.renderInContext(UIGraphicsGetCurrentContext());
|
||||
const image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
view.layer.opacity = originalOpacity;
|
||||
return image;
|
||||
}
|
||||
|
||||
export function copyLayerProperties(view: UIView, toView: UIView, customProperties?: { view?: Array<keyof UIView>; layer?: Array<keyof CALayer> }) {
|
||||
const viewPropertiesToMatch: Array<keyof UIView> = customProperties?.view || ['backgroundColor'];
|
||||
const layerPropertiesToMatch: Array<keyof CALayer> = customProperties?.layer || ['cornerRadius', 'borderWidth', 'borderColor'];
|
||||
|
||||
viewPropertiesToMatch.forEach((property) => {
|
||||
if (view[property] !== toView[property]) {
|
||||
// console.log('| -- matching view property:', property);
|
||||
view[property as any] = toView[property];
|
||||
}
|
||||
});
|
||||
|
||||
layerPropertiesToMatch.forEach((property) => {
|
||||
if (view.layer[property] !== toView.layer[property]) {
|
||||
// console.log('| -- matching layer property:', property);
|
||||
view.layer[property as any] = toView.layer[property];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function animateWithSpring(options?: { tension?: number; friction?: number; mass?: number; delay?: number; velocity?: number; animateOptions?: UIViewAnimationOptions; animations?: () => void; completion?: (finished?: boolean) => void }) {
|
||||
// for convenience, default spring settings are provided
|
||||
const opt = {
|
||||
...CORE_ANIMATION_DEFAULTS.spring,
|
||||
delay: 0,
|
||||
animateOptions: null,
|
||||
animations: null,
|
||||
completion: null,
|
||||
...(options || {}),
|
||||
};
|
||||
const { duration, damping } = getDurationWithDampingFromSpring(opt);
|
||||
|
||||
if (duration === 0) {
|
||||
UIView.animateWithDurationAnimationsCompletion(0, opt.animations, opt.completion);
|
||||
return;
|
||||
}
|
||||
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(duration, opt.delay, damping, opt.velocity, opt.animateOptions, opt.animations, opt.completion);
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
import * as AndroidUtils from './android';
|
||||
import { platformCheck } from './platform-check';
|
||||
import { getNativeApplication, android as androidApp } from '../application';
|
||||
import { Trace } from '../trace';
|
||||
import { numberHasDecimals, numberIs64Bit } from './types';
|
||||
|
||||
const globalThis = global;
|
||||
|
||||
export function dataDeserialize(nativeData?: any) {
|
||||
if (nativeData === null || typeof nativeData !== 'object') {
|
||||
return nativeData;
|
||||
@@ -143,183 +140,13 @@ export function dataSerialize(data?: any, wrapPrimitives?: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace AndroidUtils {
|
||||
let application: globalThis.android.app.Application;
|
||||
let applicationContext: globalThis.android.content.Context;
|
||||
let contextResources: globalThis.android.content.res.Resources;
|
||||
let packageName: string;
|
||||
export function getApplicationContext() {
|
||||
if (!applicationContext) {
|
||||
applicationContext = getApplication().getApplicationContext();
|
||||
}
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
export function getCurrentActivity() {
|
||||
if (!androidApp) {
|
||||
return null;
|
||||
}
|
||||
return androidApp.foregroundActivity || androidApp.startActivity;
|
||||
}
|
||||
export function getApplication() {
|
||||
if (!application) {
|
||||
application = <globalThis.android.app.Application>getNativeApplication();
|
||||
}
|
||||
|
||||
return application;
|
||||
}
|
||||
export function getResources() {
|
||||
if (!contextResources) {
|
||||
contextResources = getApplication().getResources();
|
||||
}
|
||||
|
||||
return contextResources;
|
||||
}
|
||||
function getPackageName() {
|
||||
if (!packageName) {
|
||||
packageName = getApplicationContext().getPackageName();
|
||||
}
|
||||
|
||||
return packageName;
|
||||
}
|
||||
|
||||
let inputMethodManager: globalThis.android.view.inputmethod.InputMethodManager;
|
||||
export function getInputMethodManager(): globalThis.android.view.inputmethod.InputMethodManager {
|
||||
if (!inputMethodManager) {
|
||||
inputMethodManager = <globalThis.android.view.inputmethod.InputMethodManager>getApplicationContext().getSystemService(globalThis.android.content.Context.INPUT_METHOD_SERVICE);
|
||||
}
|
||||
|
||||
return inputMethodManager;
|
||||
}
|
||||
|
||||
export function showSoftInput(nativeView: globalThis.android.view.View): void {
|
||||
const inputManager = getInputMethodManager();
|
||||
if (inputManager && nativeView instanceof globalThis.android.view.View) {
|
||||
inputManager.showSoftInput(nativeView, globalThis.android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
|
||||
export function dismissSoftInput(nativeView?: globalThis.android.view.View): void {
|
||||
const inputManager = getInputMethodManager();
|
||||
let windowToken: globalThis.android.os.IBinder;
|
||||
|
||||
if (nativeView instanceof globalThis.android.view.View) {
|
||||
if (!nativeView.hasFocus()) {
|
||||
return;
|
||||
}
|
||||
windowToken = nativeView.getWindowToken();
|
||||
} else if (getCurrentActivity() instanceof androidx.appcompat.app.AppCompatActivity) {
|
||||
const decorView = getCurrentActivity().getWindow().getDecorView();
|
||||
if (decorView) {
|
||||
windowToken = decorView.getWindowToken();
|
||||
decorView.requestFocus();
|
||||
} else {
|
||||
windowToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputManager && windowToken) {
|
||||
inputManager.hideSoftInputFromWindow(windowToken, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export namespace collections {
|
||||
export function stringArrayToStringSet(str: string[]): java.util.HashSet<string> {
|
||||
const hashSet = new java.util.HashSet<string>();
|
||||
if (str !== undefined) {
|
||||
for (const element in str) {
|
||||
hashSet.add('' + str[element]);
|
||||
}
|
||||
}
|
||||
|
||||
return hashSet;
|
||||
}
|
||||
|
||||
export function stringSetToStringArray(stringSet: any): string[] {
|
||||
const arr = [];
|
||||
if (stringSet !== undefined) {
|
||||
const it = stringSet.iterator();
|
||||
while (it.hasNext()) {
|
||||
const element = '' + it.next();
|
||||
arr.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace resources {
|
||||
let attr;
|
||||
const attrCache = new Map<string, number>();
|
||||
|
||||
export function getDrawableId(name) {
|
||||
return getId(':drawable/' + name);
|
||||
}
|
||||
|
||||
export function getStringId(name) {
|
||||
return getId(':string/' + name);
|
||||
}
|
||||
|
||||
export function getId(name: string): number {
|
||||
const resources = getResources();
|
||||
const packageName = getPackageName();
|
||||
const uri = packageName + name;
|
||||
|
||||
return resources.getIdentifier(uri, null, null);
|
||||
}
|
||||
export function getResource(name: string, type?: string): number {
|
||||
return getResources().getIdentifier(name, type, getPackageName());
|
||||
}
|
||||
export function getPalleteColor(name: string, context: globalThis.android.content.Context): number {
|
||||
return getPaletteColor(name, context);
|
||||
}
|
||||
export function getPaletteColor(name: string, context: globalThis.android.content.Context): number {
|
||||
if (attrCache.has(name)) {
|
||||
return attrCache.get(name);
|
||||
}
|
||||
|
||||
let result = 0;
|
||||
try {
|
||||
if (!attr) {
|
||||
attr = java.lang.Class.forName('androidx.appcompat.R$attr');
|
||||
}
|
||||
|
||||
let colorID = 0;
|
||||
const field = attr.getField(name);
|
||||
if (field) {
|
||||
colorID = field.getInt(null);
|
||||
}
|
||||
|
||||
if (colorID) {
|
||||
const typedValue = new globalThis.android.util.TypedValue();
|
||||
context.getTheme().resolveAttribute(colorID, typedValue, true);
|
||||
result = typedValue.data;
|
||||
}
|
||||
} catch (ex) {
|
||||
Trace.write('Cannot get pallete color: ' + name, Trace.categories.Error, Trace.messageType.error);
|
||||
}
|
||||
|
||||
attrCache.set(name, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function isRealDevice(): boolean {
|
||||
const fingerprint = globalThis.android.os.Build.FINGERPRINT;
|
||||
|
||||
return fingerprint != null && (fingerprint.indexOf('vbox') > -1 || fingerprint.indexOf('generic') > -1);
|
||||
}
|
||||
}
|
||||
export import android = AndroidUtils;
|
||||
|
||||
/**
|
||||
* @deprecated Use `Utils.android` instead.
|
||||
*/
|
||||
export import ad = AndroidUtils;
|
||||
|
||||
export import android = AndroidUtils;
|
||||
|
||||
// these don't exist on Android.Stub them to empty functions.
|
||||
export const iOSNativeHelper = platformCheck('Utils.iOSNativeHelper');
|
||||
export const ios = platformCheck('Utils.ios');
|
||||
|
||||
458
packages/core/utils/native-helper.d.ts
vendored
458
packages/core/utils/native-helper.d.ts
vendored
@@ -9,277 +9,279 @@ export function dataSerialize(data?: any, wrapPrimitives?: boolean): any;
|
||||
*/
|
||||
export function dataDeserialize(nativeData?: any): any;
|
||||
|
||||
/**
|
||||
* Module with android specific utilities.
|
||||
*/
|
||||
declare namespace AndroidUtils {
|
||||
/**
|
||||
* Gets the native Android application instance.
|
||||
*/
|
||||
export function getApplication(): any; /* android.app.Application */
|
||||
// /**
|
||||
// * Module with android specific utilities.
|
||||
// */
|
||||
// declare namespace AndroidUtils {
|
||||
// /**
|
||||
// * Gets the native Android application instance.
|
||||
// */
|
||||
// export function getApplication(): any; /* android.app.Application */
|
||||
|
||||
/**
|
||||
* Get the current native Android activity.
|
||||
*/
|
||||
export function getCurrentActivity(): any; /* android.app.Activity */
|
||||
/**
|
||||
* Gets the native Android application resources.
|
||||
*/
|
||||
export function getResources(): any; /* android.content.res.Resources */
|
||||
// /**
|
||||
// * Get the current native Android activity.
|
||||
// */
|
||||
// export function getCurrentActivity(): any; /* android.app.Activity */
|
||||
// /**
|
||||
// * Gets the native Android application resources.
|
||||
// */
|
||||
// export function getResources(): any; /* android.content.res.Resources */
|
||||
|
||||
/**
|
||||
* Gets the Android application context.
|
||||
*/
|
||||
export function getApplicationContext(): any; /* android.content.Context */
|
||||
// /**
|
||||
// * Gets the Android application context.
|
||||
// */
|
||||
// export function getApplicationContext(): any; /* android.content.Context */
|
||||
|
||||
/**
|
||||
* Gets the native Android input method manager.
|
||||
*/
|
||||
export function getInputMethodManager(): any; /* android.view.inputmethod.InputMethodManager */
|
||||
// /**
|
||||
// * Gets the native Android input method manager.
|
||||
// */
|
||||
// export function getInputMethodManager(): any; /* android.view.inputmethod.InputMethodManager */
|
||||
|
||||
/**
|
||||
* Hides the soft input method, usually a soft keyboard.
|
||||
*/
|
||||
export function dismissSoftInput(nativeView?: any /* android.view.View */): void;
|
||||
// /**
|
||||
// * Hides the soft input method, usually a soft keyboard.
|
||||
// */
|
||||
// export function dismissSoftInput(nativeView?: any /* android.view.View */): void;
|
||||
|
||||
/**
|
||||
* Shows the soft input method, usually a soft keyboard.
|
||||
*/
|
||||
export function showSoftInput(nativeView: any /* android.view.View */): void;
|
||||
// /**
|
||||
// * Shows the soft input method, usually a soft keyboard.
|
||||
// */
|
||||
// export function showSoftInput(nativeView: any /* android.view.View */): void;
|
||||
|
||||
/**
|
||||
* Utility module dealing with some android collections.
|
||||
*/
|
||||
namespace collections {
|
||||
/**
|
||||
* Converts string array into a String [hash set](http://developer.android.com/reference/java/util/HashSet.html).
|
||||
* @param str - An array of strings to convert.
|
||||
*/
|
||||
export function stringArrayToStringSet(str: string[]): any;
|
||||
// /**
|
||||
// * Utility module dealing with some android collections.
|
||||
// */
|
||||
// namespace collections {
|
||||
// /**
|
||||
// * Converts string array into a String [hash set](http://developer.android.com/reference/java/util/HashSet.html).
|
||||
// * @param str - An array of strings to convert.
|
||||
// */
|
||||
// export function stringArrayToStringSet(str: string[]): any;
|
||||
|
||||
/**
|
||||
* Converts string hash set into array of strings.
|
||||
* @param stringSet - A string hash set to convert.
|
||||
*/
|
||||
export function stringSetToStringArray(stringSet: any): string[];
|
||||
}
|
||||
// /**
|
||||
// * Converts string hash set into array of strings.
|
||||
// * @param stringSet - A string hash set to convert.
|
||||
// */
|
||||
// export function stringSetToStringArray(stringSet: any): string[];
|
||||
// }
|
||||
|
||||
/**
|
||||
* Utility module related to android resources.
|
||||
*/
|
||||
export namespace resources {
|
||||
/**
|
||||
* Gets the drawable id from a given name.
|
||||
* @param name - Name of the resource.
|
||||
*/
|
||||
export function getDrawableId(name);
|
||||
// /**
|
||||
// * Utility module related to android resources.
|
||||
// */
|
||||
// export namespace resources {
|
||||
// /**
|
||||
// * Gets the drawable id from a given name.
|
||||
// * @param name - Name of the resource.
|
||||
// */
|
||||
// export function getDrawableId(name);
|
||||
|
||||
/**
|
||||
* Gets the string id from a given name.
|
||||
* @param name - Name of the resource.
|
||||
*/
|
||||
export function getStringId(name);
|
||||
// /**
|
||||
// * Gets the string id from a given name.
|
||||
// * @param name - Name of the resource.
|
||||
// */
|
||||
// export function getStringId(name);
|
||||
|
||||
/**
|
||||
* Gets the id from a given name.
|
||||
* @param name - Name of the resource.
|
||||
*/
|
||||
export function getId(name: string): number;
|
||||
// /**
|
||||
// * Gets the id from a given name.
|
||||
// * @param name - Name of the resource.
|
||||
// */
|
||||
// export function getId(name: string): number;
|
||||
|
||||
/**
|
||||
* Gets the id from a given name with optional type.
|
||||
* This sets an explicit package name.
|
||||
* https://developer.android.com/reference/android/content/res/Resources#getIdentifier(java.lang.String,%20java.lang.String,%20java.lang.String)
|
||||
* @param name - Name of the resource.
|
||||
* @param type - (Optional) type
|
||||
*/
|
||||
export function getResource(name: string, type?: string): number;
|
||||
// /**
|
||||
// * Gets the id from a given name with optional type.
|
||||
// * This sets an explicit package name.
|
||||
// * https://developer.android.com/reference/android/content/res/Resources#getIdentifier(java.lang.String,%20java.lang.String,%20java.lang.String)
|
||||
// * @param name - Name of the resource.
|
||||
// * @param type - (Optional) type
|
||||
// */
|
||||
// export function getResource(name: string, type?: string): number;
|
||||
|
||||
/**
|
||||
* [Obsolete - please use getPaletteColor] Gets a color from current theme.
|
||||
* @param name - Name of the color
|
||||
*/
|
||||
export function getPalleteColor();
|
||||
// /**
|
||||
// * [Obsolete - please use getPaletteColor] Gets a color from current theme.
|
||||
// * @param name - Name of the color
|
||||
// */
|
||||
// export function getPalleteColor();
|
||||
|
||||
/**
|
||||
* Gets a color from the current theme.
|
||||
* @param name - Name of the color resource.
|
||||
*/
|
||||
export function getPaletteColor(name: string, context: any /* android.content.Context */): number;
|
||||
}
|
||||
// /**
|
||||
// * Gets a color from the current theme.
|
||||
// * @param name - Name of the color resource.
|
||||
// */
|
||||
// export function getPaletteColor(name: string, context: any /* android.content.Context */): number;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Checks whether the application is running on real device and not on emulator.
|
||||
*/
|
||||
export function isRealDevice(): boolean;
|
||||
}
|
||||
// /**
|
||||
// * Checks whether the application is running on real device and not on emulator.
|
||||
// */
|
||||
// export function isRealDevice(): boolean;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Module with ios specific utilities.
|
||||
*/
|
||||
declare namespace iOSUtils {
|
||||
// Common properties between UILabel, UITextView and UITextField
|
||||
export interface TextUIView {
|
||||
font: any;
|
||||
textAlignment: number;
|
||||
textColor: any;
|
||||
text: string;
|
||||
attributedText: any;
|
||||
lineBreakMode: number;
|
||||
numberOfLines: number;
|
||||
}
|
||||
// /**
|
||||
// * Module with ios specific utilities.
|
||||
// */
|
||||
// declare namespace iOSUtils {
|
||||
// // Common properties between UILabel, UITextView and UITextField
|
||||
// export interface TextUIView {
|
||||
// font: any;
|
||||
// textAlignment: number;
|
||||
// textColor: any;
|
||||
// text: string;
|
||||
// attributedText: any;
|
||||
// lineBreakMode: number;
|
||||
// numberOfLines: number;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Utility module dealing with some iOS collections.
|
||||
*/
|
||||
export namespace collections {
|
||||
/**
|
||||
* Converts JavaScript array to [NSArray](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/).
|
||||
* @param str - JavaScript string array to convert.
|
||||
*/
|
||||
export function jsArrayToNSArray<T>(str: T[]): NSArray<T>;
|
||||
// /**
|
||||
// * Utility module dealing with some iOS collections.
|
||||
// */
|
||||
// export namespace collections {
|
||||
// /**
|
||||
// * Converts JavaScript array to [NSArray](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/).
|
||||
// * @param str - JavaScript string array to convert.
|
||||
// */
|
||||
// export function jsArrayToNSArray<T>(str: T[]): NSArray<T>;
|
||||
|
||||
/**
|
||||
* Converts NSArray to JavaScript array.
|
||||
* @param a - NSArray to convert.
|
||||
*/
|
||||
export function nsArrayToJSArray<T>(a: NSArray<T>): T[];
|
||||
}
|
||||
// /**
|
||||
// * Converts NSArray to JavaScript array.
|
||||
// * @param a - NSArray to convert.
|
||||
// */
|
||||
// export function nsArrayToJSArray<T>(a: NSArray<T>): T[];
|
||||
// }
|
||||
|
||||
/**
|
||||
* Get the root UIViewController of the app
|
||||
*/
|
||||
export function getRootViewController(): any; /* UIViewController */
|
||||
// /**
|
||||
// * Get the root UIViewController of the app
|
||||
// */
|
||||
// export function getRootViewController(): any; /* UIViewController */
|
||||
|
||||
/**
|
||||
* Get the UIWindow of the app
|
||||
*/
|
||||
export function getWindow(): any; /* UIWindow */
|
||||
// /**
|
||||
// * Get the UIWindow of the app
|
||||
// */
|
||||
// export function getWindow(): any; /* UIWindow */
|
||||
|
||||
/**
|
||||
* Set the window background color of base view of the app.
|
||||
* Often this is shown when opening a modal as the view underneath scales down revealing the window color.
|
||||
* @param value color (hex, rgb, rgba, etc.)
|
||||
*/
|
||||
export function setWindowBackgroundColor(value: string): void;
|
||||
// /**
|
||||
// * Set the window background color of base view of the app.
|
||||
// * Often this is shown when opening a modal as the view underneath scales down revealing the window color.
|
||||
// * @param value color (hex, rgb, rgba, etc.)
|
||||
// */
|
||||
// export function setWindowBackgroundColor(value: string): void;
|
||||
|
||||
/**
|
||||
* Data serialize and deserialize helpers
|
||||
*/
|
||||
export function dataSerialize(data?: any): any;
|
||||
export function dataDeserialize(nativeData?: any): any;
|
||||
// /**
|
||||
// * Data serialize and deserialize helpers
|
||||
// */
|
||||
// export function dataSerialize(data?: any): any;
|
||||
// export function dataDeserialize(nativeData?: any): any;
|
||||
|
||||
/**
|
||||
* @deprecated use application.orientation instead
|
||||
*
|
||||
* Gets an information about if current mode is Landscape.
|
||||
*/
|
||||
export function isLandscape(): boolean;
|
||||
// /**
|
||||
// * @deprecated use application.orientation instead
|
||||
// *
|
||||
// * Gets an information about if current mode is Landscape.
|
||||
// */
|
||||
// export function isLandscape(): boolean;
|
||||
|
||||
/**
|
||||
* Gets the iOS device major version (for 8.1 will return 8).
|
||||
*/
|
||||
export const MajorVersion: number;
|
||||
// /**
|
||||
// * Gets the iOS device major version (for 8.1 will return 8).
|
||||
// */
|
||||
// export const MajorVersion: number;
|
||||
|
||||
/**
|
||||
* Opens file with associated application.
|
||||
* @param filePath The file path.
|
||||
*/
|
||||
export function openFile(filePath: string): boolean;
|
||||
// /**
|
||||
// * Opens file with associated application.
|
||||
// * @param filePath The file path.
|
||||
// */
|
||||
// export function openFile(filePath: string): boolean;
|
||||
|
||||
/**
|
||||
* Joins an array of file paths.
|
||||
* @param paths An array of paths.
|
||||
* Returns the joined path.
|
||||
*/
|
||||
export function joinPaths(...paths: string[]): string;
|
||||
// /**
|
||||
// * Joins an array of file paths.
|
||||
// * @param paths An array of paths.
|
||||
// * Returns the joined path.
|
||||
// */
|
||||
// export function joinPaths(...paths: string[]): string;
|
||||
|
||||
/**
|
||||
* Gets the root folder for the current application. This Folder is private for the application and not accessible from Users/External apps.
|
||||
* iOS - this folder is read-only and contains the app and all its resources.
|
||||
*/
|
||||
export function getCurrentAppPath(): string;
|
||||
// /**
|
||||
// * Gets the root folder for the current application. This Folder is private for the application and not accessible from Users/External apps.
|
||||
// * iOS - this folder is read-only and contains the app and all its resources.
|
||||
// */
|
||||
// export function getCurrentAppPath(): string;
|
||||
|
||||
/**
|
||||
* Gets the currently visible(topmost) UIViewController.
|
||||
* @param rootViewController The root UIViewController instance to start searching from (normally window.rootViewController).
|
||||
* Returns the visible UIViewController.
|
||||
*/
|
||||
export function getVisibleViewController(rootViewController: any /* UIViewController*/): any; /* UIViewController*/
|
||||
// /**
|
||||
// * Gets the currently visible(topmost) UIViewController.
|
||||
// * @param rootViewController The root UIViewController instance to start searching from (normally window.rootViewController).
|
||||
// * Returns the visible UIViewController.
|
||||
// */
|
||||
// export function getVisibleViewController(rootViewController: any /* UIViewController*/): any; /* UIViewController*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param transform Applies a rotation transform over X,Y and Z axis
|
||||
* @param x Rotation over X axis in degrees
|
||||
* @param y Rotation over Y axis in degrees
|
||||
* @param z Rotation over Z axis in degrees
|
||||
*/
|
||||
export function applyRotateTransform(transform: any /* CATransform3D*/, x: number, y: number, z: number): any; /* CATransform3D*/
|
||||
// /**
|
||||
// *
|
||||
// * @param transform Applies a rotation transform over X,Y and Z axis
|
||||
// * @param x Rotation over X axis in degrees
|
||||
// * @param y Rotation over Y axis in degrees
|
||||
// * @param z Rotation over Z axis in degrees
|
||||
// */
|
||||
// export function applyRotateTransform(transform: any /* CATransform3D*/, x: number, y: number, z: number): any; /* CATransform3D*/
|
||||
|
||||
/**
|
||||
* @param nativeView UIView to find shadow layer with
|
||||
* @param name Name of the shadow layer if looking for specifically named layer
|
||||
* @param create should we create a new layer if not found
|
||||
*/
|
||||
export function getShadowLayer(nativeView: any /* UIView */, name?: string, create?: boolean): any; /* CALayer */
|
||||
// /**
|
||||
// * @param nativeView UIView to find shadow layer with
|
||||
// * @param name Name of the shadow layer if looking for specifically named layer
|
||||
// * @param create should we create a new layer if not found
|
||||
// */
|
||||
// export function getShadowLayer(nativeView: any /* UIView */, name?: string, create?: boolean): any; /* CALayer */
|
||||
|
||||
/**
|
||||
* Create a UIDocumentInteractionControllerDelegate implementation for use with UIDocumentInteractionController
|
||||
*/
|
||||
export function createUIDocumentInteractionControllerDelegate(): any;
|
||||
// /**
|
||||
// * Create a UIDocumentInteractionControllerDelegate implementation for use with UIDocumentInteractionController
|
||||
// */
|
||||
// export function createUIDocumentInteractionControllerDelegate(): any;
|
||||
|
||||
/**
|
||||
* Checks whether the application is running on real device and not on simulator.
|
||||
*/
|
||||
export function isRealDevice(): boolean;
|
||||
// /**
|
||||
// * Checks whether the application is running on real device and not on simulator.
|
||||
// */
|
||||
// export function isRealDevice(): boolean;
|
||||
|
||||
/**
|
||||
* Debug utility to insert CGRect values into logging output.
|
||||
* Note: when printing a CGRect directly it will print blank so this helps show the values.
|
||||
* @param rect CGRect
|
||||
*/
|
||||
export function printCGRect(rect: CGRect): void;
|
||||
// /**
|
||||
// * Debug utility to insert CGRect values into logging output.
|
||||
// * Note: when printing a CGRect directly it will print blank so this helps show the values.
|
||||
// * @param rect CGRect
|
||||
// */
|
||||
// export function printCGRect(rect: CGRect): void;
|
||||
|
||||
/**
|
||||
* Take a snapshot of a View on screen.
|
||||
* @param view view to snapshot
|
||||
* @param scale screen scale
|
||||
*/
|
||||
export function snapshotView(view: UIView, scale: number): UIImage;
|
||||
// /**
|
||||
// * Take a snapshot of a View on screen.
|
||||
// * @param view view to snapshot
|
||||
// * @param scale screen scale
|
||||
// */
|
||||
// export function snapshotView(view: UIView, scale: number): UIImage;
|
||||
|
||||
/**
|
||||
* Copy layer properties from one view to another.
|
||||
* @param view a view to copy layer properties to
|
||||
* @param toView a view to copy later properties from
|
||||
* @param (optional) custom properties to copy between both views
|
||||
*/
|
||||
export function copyLayerProperties(view: UIView, toView: UIView, customProperties?: { view?: Array<string> /* Array<keyof UIView> */; layer?: Array<string> /* Array<keyof CALayer> */ }): void;
|
||||
// /**
|
||||
// * Copy layer properties from one view to another.
|
||||
// * @param view a view to copy layer properties to
|
||||
// * @param toView a view to copy later properties from
|
||||
// * @param (optional) custom properties to copy between both views
|
||||
// */
|
||||
// export function copyLayerProperties(view: UIView, toView: UIView, customProperties?: { view?: Array<string> /* Array<keyof UIView> */; layer?: Array<string> /* Array<keyof CALayer> */ }): void;
|
||||
|
||||
/**
|
||||
* Animate views with a configurable spring effect
|
||||
* @param options various animation settings for the spring
|
||||
* - tension: number
|
||||
* - friction: number
|
||||
* - mass: number
|
||||
* - delay: number
|
||||
* - velocity: number
|
||||
* - animateOptions: UIViewAnimationOptions
|
||||
* - animations: () => void, Callback containing the property changes you want animated
|
||||
* - completion: (finished: boolean) => void, Callback when animation is finished
|
||||
*/
|
||||
export function animateWithSpring(options?: { tension?: number; friction?: number; mass?: number; delay?: number; velocity?: number; animateOptions?: UIViewAnimationOptions; animations?: () => void; completion?: (finished?: boolean) => void });
|
||||
}
|
||||
// /**
|
||||
// * Animate views with a configurable spring effect
|
||||
// * @param options various animation settings for the spring
|
||||
// * - tension: number
|
||||
// * - friction: number
|
||||
// * - mass: number
|
||||
// * - delay: number
|
||||
// * - velocity: number
|
||||
// * - animateOptions: UIViewAnimationOptions
|
||||
// * - animations: () => void, Callback containing the property changes you want animated
|
||||
// * - completion: (finished: boolean) => void, Callback when animation is finished
|
||||
// */
|
||||
// export function animateWithSpring(options?: { tension?: number; friction?: number; mass?: number; delay?: number; velocity?: number; animateOptions?: UIViewAnimationOptions; animations?: () => void; completion?: (finished?: boolean) => void });
|
||||
// }
|
||||
|
||||
import * as AndroidUtils from './android';
|
||||
export import android = AndroidUtils;
|
||||
|
||||
/**
|
||||
* @deprecated use Utils.android instead.
|
||||
*/
|
||||
export import ad = AndroidUtils;
|
||||
|
||||
export import android = AndroidUtils;
|
||||
import * as iOSUtils from './ios';
|
||||
export import ios = iOSUtils;
|
||||
|
||||
/**
|
||||
* @deprecated use Utils.ios instead.
|
||||
*/
|
||||
export import iOSNativeHelper = iOSUtils;
|
||||
|
||||
export import ios = iOSUtils;
|
||||
|
||||
@@ -1,33 +1,7 @@
|
||||
import * as iOSUtils from './ios';
|
||||
import { platformCheck } from './platform-check';
|
||||
import { Color } from '../color';
|
||||
import { Trace } from '../trace';
|
||||
import { CORE_ANIMATION_DEFAULTS, getDurationWithDampingFromSpring } from './common';
|
||||
import { getClass, isNullOrUndefined, numberHasDecimals, numberIs64Bit } from './types';
|
||||
|
||||
declare let UIImagePickerControllerSourceType: any;
|
||||
|
||||
const radToDeg = Math.PI / 180;
|
||||
|
||||
function isOrientationLandscape(orientation: number) {
|
||||
return orientation === UIDeviceOrientation.LandscapeLeft /* 3 */ || orientation === UIDeviceOrientation.LandscapeRight /* 4 */;
|
||||
}
|
||||
|
||||
function openFileAtRootModule(filePath: string): boolean {
|
||||
try {
|
||||
const appPath = iOSNativeHelper.getCurrentAppPath();
|
||||
const path = iOSNativeHelper.isRealDevice() ? filePath.replace('~', appPath) : filePath;
|
||||
|
||||
const controller = UIDocumentInteractionController.interactionControllerWithURL(NSURL.fileURLWithPath(path));
|
||||
controller.delegate = iOSNativeHelper.createUIDocumentInteractionControllerDelegate();
|
||||
|
||||
return controller.presentPreviewAnimated(true);
|
||||
} catch (e) {
|
||||
Trace.write('Error in openFile', Trace.categories.Error, Trace.messageType.error);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function dataDeserialize(nativeData?: any) {
|
||||
if (isNullOrUndefined(nativeData)) {
|
||||
// some native values will already be js null values
|
||||
@@ -113,318 +87,13 @@ export function dataSerialize(data: any, wrapPrimitives: boolean = false) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace iOSUtils {
|
||||
// TODO: remove for NativeScript 9.0
|
||||
export function getter<T>(_this: any, property: T | { (): T }): T {
|
||||
console.log('utils.ios.getter() is deprecated; use the respective native property instead');
|
||||
if (typeof property === 'function') {
|
||||
return (<{ (): T }>property).call(_this);
|
||||
} else {
|
||||
return <T>property;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace collections {
|
||||
export function jsArrayToNSArray<T>(str: T[]): NSArray<T> {
|
||||
return NSArray.arrayWithArray(str);
|
||||
}
|
||||
|
||||
export function nsArrayToJSArray<T>(a: NSArray<T>): Array<T> {
|
||||
const arr = [];
|
||||
if (a !== undefined) {
|
||||
const count = a.count;
|
||||
for (let i = 0; i < count; i++) {
|
||||
arr.push(a.objectAtIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
export function getRootViewController(): UIViewController {
|
||||
const win = getWindow();
|
||||
let vc = win && win.rootViewController;
|
||||
while (vc && vc.presentedViewController) {
|
||||
vc = vc.presentedViewController;
|
||||
}
|
||||
return vc;
|
||||
}
|
||||
|
||||
export function getWindow(): UIWindow {
|
||||
const app = UIApplication.sharedApplication;
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
return app.keyWindow || (app.windows && app.windows.count > 0 && app.windows.objectAtIndex(0));
|
||||
}
|
||||
|
||||
export function setWindowBackgroundColor(value: string) {
|
||||
const win = getWindow();
|
||||
if (win) {
|
||||
const bgColor = new Color(value);
|
||||
win.backgroundColor = bgColor.ios;
|
||||
const rootVc = getRootViewController();
|
||||
if (rootVc?.view) {
|
||||
rootVc.view.backgroundColor = bgColor.ios;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isLandscape(): boolean {
|
||||
console.log('utils.ios.isLandscape() is deprecated; use application.orientation instead');
|
||||
|
||||
const deviceOrientation = UIDevice.currentDevice.orientation;
|
||||
const statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
|
||||
|
||||
const isDeviceOrientationLandscape = isOrientationLandscape(deviceOrientation);
|
||||
const isStatusBarOrientationLandscape = isOrientationLandscape(statusBarOrientation);
|
||||
|
||||
return isDeviceOrientationLandscape || isStatusBarOrientationLandscape;
|
||||
}
|
||||
|
||||
export const MajorVersion = NSString.stringWithString(UIDevice.currentDevice.systemVersion).intValue;
|
||||
|
||||
export function openFile(filePath: string): boolean {
|
||||
console.log('utils.ios.openFile() is deprecated; use utils.openFile() instead');
|
||||
|
||||
return openFileAtRootModule(filePath);
|
||||
}
|
||||
|
||||
export function getCurrentAppPath(): string {
|
||||
const currentDir = __dirname;
|
||||
const tnsModulesIndex = currentDir.indexOf('/tns_modules');
|
||||
|
||||
// Module not hosted in ~/tns_modules when bundled. Use current dir.
|
||||
let appPath = currentDir;
|
||||
if (tnsModulesIndex !== -1) {
|
||||
// Strip part after tns_modules to obtain app root
|
||||
appPath = currentDir.substring(0, tnsModulesIndex);
|
||||
}
|
||||
|
||||
return appPath;
|
||||
}
|
||||
|
||||
export function joinPaths(...paths: string[]): string {
|
||||
if (!paths || paths.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return NSString.stringWithString(NSString.pathWithComponents(<any>paths)).stringByStandardizingPath;
|
||||
}
|
||||
|
||||
export function getVisibleViewController(rootViewController: UIViewController): UIViewController {
|
||||
let viewController = rootViewController;
|
||||
|
||||
while (viewController && viewController.presentedViewController) {
|
||||
viewController = viewController.presentedViewController;
|
||||
}
|
||||
return viewController;
|
||||
}
|
||||
|
||||
export function applyRotateTransform(transform: CATransform3D, x: number, y: number, z: number): CATransform3D {
|
||||
if (x) {
|
||||
transform = CATransform3DRotate(transform, x * radToDeg, 1, 0, 0);
|
||||
}
|
||||
|
||||
if (y) {
|
||||
transform = CATransform3DRotate(transform, y * radToDeg, 0, 1, 0);
|
||||
}
|
||||
|
||||
if (z) {
|
||||
transform = CATransform3DRotate(transform, z * radToDeg, 0, 0, 1);
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
export function getShadowLayer(nativeView: UIView, name: string = 'ns-shadow-layer', create: boolean = true): CALayer {
|
||||
return nativeView.layer;
|
||||
|
||||
console.log(`--- ${create ? 'CREATE' : 'READ'}`);
|
||||
|
||||
/**
|
||||
* UIView
|
||||
* -> Shadow
|
||||
*
|
||||
*
|
||||
* UIView
|
||||
* -> UIView
|
||||
* -> Shadow
|
||||
*/
|
||||
|
||||
if (!nativeView) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!nativeView.layer) {
|
||||
// should never hit this?
|
||||
console.log('- no layer! -');
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the nativeView's layer is the shadow layer?
|
||||
if (nativeView.layer.name === name) {
|
||||
console.log('- found shadow layer - reusing.');
|
||||
return nativeView.layer;
|
||||
}
|
||||
|
||||
console.log('>> layer :', nativeView.layer);
|
||||
if (nativeView.layer.sublayers?.count) {
|
||||
const count = nativeView.layer.sublayers.count;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const subLayer = nativeView.layer.sublayers.objectAtIndex(i);
|
||||
|
||||
console.log(`>> subLayer ${i + 1}/${count} :`, subLayer);
|
||||
console.log(`>> subLayer ${i + 1}/${count} name :`, subLayer.name);
|
||||
|
||||
if (subLayer.name === name) {
|
||||
console.log('- found shadow sublayer - reusing.');
|
||||
return subLayer;
|
||||
}
|
||||
}
|
||||
// if (nativeView instanceof UITextView) {
|
||||
// return nativeView.layer.sublayers.objectAtIndex(1);
|
||||
// } else {
|
||||
// return nativeView.layer.sublayers.objectAtIndex(nativeView.layer.sublayers.count - 1);
|
||||
// }
|
||||
}
|
||||
// else {
|
||||
// layer = nativeView.layer;
|
||||
// }
|
||||
|
||||
// we're not interested in creating a new layer
|
||||
if (!create) {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`- adding a new layer for - ${name}`);
|
||||
|
||||
const viewLayer = nativeView.layer;
|
||||
const newLayer = CALayer.layer();
|
||||
|
||||
newLayer.name = name;
|
||||
newLayer.zPosition = 0.0;
|
||||
// nativeView.layer.insertSublayerBelow(newLayer, nativeView.layer)
|
||||
// newLayer.insertSublayerAtIndex(nativeView.layer, 0)
|
||||
// nativeView.layer.zPosition = 1.0;
|
||||
// nativeView.layer.addSublayer(newLayer);
|
||||
|
||||
// nativeView.layer = CALayer.layer()
|
||||
|
||||
nativeView.layer.insertSublayerAtIndex(newLayer, 0);
|
||||
// nativeView.layer.insertSublayerAtIndex(viewLayer, 1)
|
||||
|
||||
// nativeView.layer.replaceSublayerWith(newLayer, nativeView.layer);
|
||||
|
||||
return newLayer;
|
||||
}
|
||||
|
||||
export function createUIDocumentInteractionControllerDelegate(): NSObject {
|
||||
@NativeClass
|
||||
class UIDocumentInteractionControllerDelegateImpl extends NSObject implements UIDocumentInteractionControllerDelegate {
|
||||
public static ObjCProtocols = [UIDocumentInteractionControllerDelegate];
|
||||
|
||||
public getViewController(): UIViewController {
|
||||
const app = UIApplication.sharedApplication;
|
||||
|
||||
return app.keyWindow.rootViewController;
|
||||
}
|
||||
|
||||
public documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) {
|
||||
return this.getViewController();
|
||||
}
|
||||
|
||||
public documentInteractionControllerViewForPreview(controller: UIDocumentInteractionController) {
|
||||
return this.getViewController().view;
|
||||
}
|
||||
|
||||
public documentInteractionControllerRectForPreview(controller: UIDocumentInteractionController): CGRect {
|
||||
return this.getViewController().view.frame;
|
||||
}
|
||||
}
|
||||
return new UIDocumentInteractionControllerDelegateImpl();
|
||||
}
|
||||
|
||||
export function isRealDevice() {
|
||||
try {
|
||||
// https://stackoverflow.com/a/5093092/4936697
|
||||
const sourceType = UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypeCamera;
|
||||
const mediaTypes = UIImagePickerController.availableMediaTypesForSourceType(sourceType);
|
||||
|
||||
return mediaTypes;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function printCGRect(rect: CGRect) {
|
||||
if (rect) {
|
||||
return `CGRect(${rect.origin.x} ${rect.origin.y} ${rect.size.width} ${rect.size.height})`;
|
||||
}
|
||||
}
|
||||
|
||||
export function snapshotView(view: UIView, scale: number): UIImage {
|
||||
if (view instanceof UIImageView) {
|
||||
return view.image;
|
||||
}
|
||||
// console.log('snapshotView view.frame:', printRect(view.frame));
|
||||
const originalOpacity = view.layer.opacity;
|
||||
view.layer.opacity = originalOpacity > 0 ? originalOpacity : 1;
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(view.frame.size.width, view.frame.size.height), false, scale);
|
||||
view.layer.renderInContext(UIGraphicsGetCurrentContext());
|
||||
const image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
view.layer.opacity = originalOpacity;
|
||||
return image;
|
||||
}
|
||||
|
||||
export function copyLayerProperties(view: UIView, toView: UIView, customProperties?: { view?: Array<keyof UIView>; layer?: Array<keyof CALayer> }) {
|
||||
const viewPropertiesToMatch: Array<keyof UIView> = customProperties?.view || ['backgroundColor'];
|
||||
const layerPropertiesToMatch: Array<keyof CALayer> = customProperties?.layer || ['cornerRadius', 'borderWidth', 'borderColor'];
|
||||
|
||||
viewPropertiesToMatch.forEach((property) => {
|
||||
if (view[property] !== toView[property]) {
|
||||
// console.log('| -- matching view property:', property);
|
||||
view[property as any] = toView[property];
|
||||
}
|
||||
});
|
||||
|
||||
layerPropertiesToMatch.forEach((property) => {
|
||||
if (view.layer[property] !== toView.layer[property]) {
|
||||
// console.log('| -- matching layer property:', property);
|
||||
view.layer[property as any] = toView.layer[property];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function animateWithSpring(options?: { tension?: number; friction?: number; mass?: number; delay?: number; velocity?: number; animateOptions?: UIViewAnimationOptions; animations?: () => void; completion?: (finished?: boolean) => void }) {
|
||||
// for convenience, default spring settings are provided
|
||||
const opt = {
|
||||
...CORE_ANIMATION_DEFAULTS.spring,
|
||||
delay: 0,
|
||||
animateOptions: null,
|
||||
animations: null,
|
||||
completion: null,
|
||||
...(options || {}),
|
||||
};
|
||||
const { duration, damping } = getDurationWithDampingFromSpring(opt);
|
||||
|
||||
if (duration === 0) {
|
||||
UIView.animateWithDurationAnimationsCompletion(0, opt.animations, opt.completion);
|
||||
return;
|
||||
}
|
||||
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(duration, opt.delay, damping, opt.velocity, opt.animateOptions, opt.animations, opt.completion);
|
||||
}
|
||||
}
|
||||
|
||||
// these don't exist on iOS. Stub them to empty functions.
|
||||
export const ad = platformCheck('Utils.ad');
|
||||
export const android = platformCheck('Utils.android');
|
||||
|
||||
export import ios = iOSUtils;
|
||||
|
||||
/**
|
||||
* @deprecated Use `Utils.ios` instead.
|
||||
*/
|
||||
export import iOSNativeHelper = iOSUtils;
|
||||
|
||||
export import ios = iOSUtils;
|
||||
|
||||
Reference in New Issue
Block a user