mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00

When embedding via 'ns embed ios', the .swift symbols may not be available and are not needed. This can be revisited in the future with project settings for embedded projects.
266 lines
8.6 KiB
TypeScript
266 lines
8.6 KiB
TypeScript
import { Color } from '../../color';
|
|
import { Trace } from '../../trace';
|
|
import { CORE_ANIMATION_DEFAULTS, getDurationWithDampingFromSpring } from '../common';
|
|
import { SDK_VERSION } from '../constants';
|
|
|
|
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 {
|
|
let window: UIWindow;
|
|
if (SDK_VERSION >= 15 && typeof NativeScriptViewFactory !== 'undefined') {
|
|
// UIWindowScene.keyWindow is only available 15+
|
|
window = NativeScriptViewFactory.getKeyWindow();
|
|
}
|
|
if (window) {
|
|
return window;
|
|
}
|
|
const app = UIApplication.sharedApplication;
|
|
if (!app) {
|
|
return;
|
|
}
|
|
return app.keyWindow || (app.windows && app.windows.count > 0 && app.windows.objectAtIndex(0));
|
|
}
|
|
|
|
export function getMainScreen(): UIScreen {
|
|
const window = getWindow();
|
|
return window ? window.screen : UIScreen.mainScreen;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* @deprecated use Utils.SDK_VERSION instead which is a float of the {major}.{minor} verison
|
|
*/
|
|
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 createUIDocumentInteractionControllerDelegate(): NSObject {
|
|
@NativeClass
|
|
class UIDocumentInteractionControllerDelegateImpl extends NSObject implements UIDocumentInteractionControllerDelegate {
|
|
public static ObjCProtocols = [UIDocumentInteractionControllerDelegate];
|
|
|
|
public getViewController(): UIViewController {
|
|
return getWindow().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();
|
|
setTimeout(() => {
|
|
// ensure set back properly on next tick
|
|
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);
|
|
}
|