diff --git a/packages/core/ui/transition/shared-transition-helper.ios.ts b/packages/core/ui/transition/shared-transition-helper.ios.ts index b0d0f6884..11a66859f 100644 --- a/packages/core/ui/transition/shared-transition-helper.ios.ts +++ b/packages/core/ui/transition/shared-transition-helper.ios.ts @@ -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; } diff --git a/packages/core/utils/android/index.ts b/packages/core/utils/android/index.ts new file mode 100644 index 000000000..3231cbcb4 --- /dev/null +++ b/packages/core/utils/android/index.ts @@ -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 = 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 = 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 { + const hashSet = new java.util.HashSet(); + 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(); + + 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); +} diff --git a/packages/core/utils/ios/index.ts b/packages/core/utils/ios/index.ts new file mode 100644 index 000000000..c9170a656 --- /dev/null +++ b/packages/core/utils/ios/index.ts @@ -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(_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 property; + } +} + +export namespace collections { + export function jsArrayToNSArray(str: T[]): NSArray { + return NSArray.arrayWithArray(str); + } + + export function nsArrayToJSArray(a: NSArray): Array { + 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(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; layer?: Array }) { + const viewPropertiesToMatch: Array = customProperties?.view || ['backgroundColor']; + const layerPropertiesToMatch: Array = 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); +} diff --git a/packages/core/utils/native-helper.android.ts b/packages/core/utils/native-helper.android.ts index db4b0ae64..de702cb1d 100644 --- a/packages/core/utils/native-helper.android.ts +++ b/packages/core/utils/native-helper.android.ts @@ -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 = 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 = 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 { - const hashSet = new java.util.HashSet(); - 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(); - - 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'); diff --git a/packages/core/utils/native-helper.d.ts b/packages/core/utils/native-helper.d.ts index ceac0f4bc..9d1756eaa 100644 --- a/packages/core/utils/native-helper.d.ts +++ b/packages/core/utils/native-helper.d.ts @@ -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(str: T[]): NSArray; +// /** +// * 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(str: T[]): NSArray; - /** - * Converts NSArray to JavaScript array. - * @param a - NSArray to convert. - */ - export function nsArrayToJSArray(a: NSArray): T[]; - } +// /** +// * Converts NSArray to JavaScript array. +// * @param a - NSArray to convert. +// */ +// export function nsArrayToJSArray(a: NSArray): 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 /* Array */; layer?: Array /* Array */ }): 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 /* Array */; layer?: Array /* Array */ }): 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; diff --git a/packages/core/utils/native-helper.ios.ts b/packages/core/utils/native-helper.ios.ts index f3ec0b7f6..71535f0db 100644 --- a/packages/core/utils/native-helper.ios.ts +++ b/packages/core/utils/native-helper.ios.ts @@ -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(_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 property; - } - } - - export namespace collections { - export function jsArrayToNSArray(str: T[]): NSArray { - return NSArray.arrayWithArray(str); - } - - export function nsArrayToJSArray(a: NSArray): Array { - 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(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; layer?: Array }) { - const viewPropertiesToMatch: Array = customProperties?.view || ['backgroundColor']; - const layerPropertiesToMatch: Array = 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;