mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 11:42:04 +08:00
chore: remove critical circular dependencies (#8114)
* chore: remove critical circular dependencies * chore: fix tslint errors * chore: remove platform specific types from interfaces * chore: update unit tests polyfills * fix: incorrect null check * chore: update api.md file * test: improve test case * chore: apply comments * test: avoid page style leaks in tests
This commit is contained in:

committed by
Alexander Vakrilov

parent
5b647bd809
commit
0ffc790d82
@ -0,0 +1,63 @@
|
||||
// cache the MeasureSpec constants here, to prevent extensive marshaling calls to and from Java
|
||||
// TODO: While this boosts the performance it is error-prone in case Google changes these constants
|
||||
export const MODE_SHIFT = 30;
|
||||
export const MODE_MASK = 0x3 << MODE_SHIFT;
|
||||
|
||||
export const UNSPECIFIED = 0 << MODE_SHIFT;
|
||||
export const EXACTLY = 1 << MODE_SHIFT;
|
||||
export const AT_MOST = 2 << MODE_SHIFT;
|
||||
|
||||
export const MEASURED_HEIGHT_STATE_SHIFT = 0x00000010; /* 16 */
|
||||
export const MEASURED_STATE_TOO_SMALL = 0x01000000;
|
||||
export const MEASURED_STATE_MASK = 0xff000000;
|
||||
export const MEASURED_SIZE_MASK = 0x00ffffff;
|
||||
|
||||
export function getMode(mode: number): string {
|
||||
switch (mode) {
|
||||
case EXACTLY:
|
||||
return "Exact";
|
||||
case AT_MOST:
|
||||
return "AtMost";
|
||||
default:
|
||||
return "Unspecified";
|
||||
}
|
||||
}
|
||||
|
||||
export function getMeasureSpecMode(spec: number): number {
|
||||
return (spec & MODE_MASK);
|
||||
}
|
||||
|
||||
export function getMeasureSpecSize(spec: number): number {
|
||||
return (spec & ~MODE_MASK);
|
||||
}
|
||||
|
||||
export function measureSpecToString(measureSpec: number): string {
|
||||
const mode = getMeasureSpecMode(measureSpec);
|
||||
const size = getMeasureSpecSize(measureSpec);
|
||||
|
||||
let text = "MeasureSpec: ";
|
||||
if (mode === UNSPECIFIED) {
|
||||
text += "UNSPECIFIED ";
|
||||
} else if (mode === EXACTLY) {
|
||||
text += "EXACTLY ";
|
||||
} else if (mode === AT_MOST) {
|
||||
text += "AT_MOST ";
|
||||
}
|
||||
|
||||
text += size;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export function round(value: number): number {
|
||||
const res = Math.floor(value + 0.5);
|
||||
if (res !== 0) {
|
||||
return res;
|
||||
} else if (value === 0) {
|
||||
return 0;
|
||||
} else if (value > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import { MODE_MASK } from "./layout-helper-common";
|
||||
import { ad } from "../native-helper";
|
||||
|
||||
export * from "./layout-helper-common";
|
||||
|
||||
let density: number;
|
||||
|
||||
let sdkVersion: number;
|
||||
let useOldMeasureSpec = false;
|
||||
|
||||
export function makeMeasureSpec(size: number, mode: number): number {
|
||||
if (sdkVersion === undefined) {
|
||||
// check whether the old layout is needed
|
||||
sdkVersion = ad.getApplicationContext().getApplicationInfo().targetSdkVersion;
|
||||
useOldMeasureSpec = sdkVersion <= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
|
||||
}
|
||||
|
||||
if (useOldMeasureSpec) {
|
||||
return size + mode;
|
||||
}
|
||||
|
||||
return (size & ~MODE_MASK) | (mode & MODE_MASK);
|
||||
}
|
||||
|
||||
export function getDisplayDensity(): number {
|
||||
if (density === undefined) {
|
||||
density = ad.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
return density;
|
||||
}
|
||||
|
||||
export function toDevicePixels(value: number): number {
|
||||
return value * getDisplayDensity();
|
||||
}
|
||||
|
||||
export function toDeviceIndependentPixels(value: number): number {
|
||||
return value / getDisplayDensity();
|
||||
}
|
||||
|
||||
export function measureNativeView(nativeView: any /* android.view.View */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number } {
|
||||
const view = <android.view.View>nativeView;
|
||||
view.measure(makeMeasureSpec(width, widthMode), makeMeasureSpec(height, heightMode));
|
||||
|
||||
return {
|
||||
width: view.getMeasuredWidth(),
|
||||
height: view.getMeasuredHeight()
|
||||
};
|
||||
}
|
77
nativescript-core/utils/layout-helper/layout-helper.d.ts
vendored
Normal file
77
nativescript-core/utils/layout-helper/layout-helper.d.ts
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
import { dip, px } from "../../ui/core/view";
|
||||
|
||||
/**
|
||||
* Bits that provide the actual measured size.
|
||||
*/
|
||||
export const MEASURED_HEIGHT_STATE_SHIFT: number;
|
||||
export const MEASURED_SIZE_MASK: number;
|
||||
export const MEASURED_STATE_MASK: number;
|
||||
export const MEASURED_STATE_TOO_SMALL: number;
|
||||
export const UNSPECIFIED: number;
|
||||
export const EXACTLY: number;
|
||||
export const AT_MOST: number;
|
||||
|
||||
/**
|
||||
* Gets layout mode from a given specification as string.
|
||||
* @param mode - The measure specification mode.
|
||||
*/
|
||||
export function getMode(mode: number): string;
|
||||
|
||||
/**
|
||||
* Gets measure specification mode from a given specification.
|
||||
* @param spec - The measure specification.
|
||||
*/
|
||||
export function getMeasureSpecMode(spec: number): number;
|
||||
|
||||
/**
|
||||
* Gets measure specification size from a given specification.
|
||||
* @param spec - The measure specification.
|
||||
*/
|
||||
export function getMeasureSpecSize(spec: number): number;
|
||||
|
||||
/**
|
||||
* Creates measure specification size from size and mode.
|
||||
* @param size - The size component of measure specification.
|
||||
* @param mode - The mode component of measure specification.
|
||||
*/
|
||||
export function makeMeasureSpec(px: number, mode: number): number;
|
||||
|
||||
/**
|
||||
* Gets display density for the current device.
|
||||
*/
|
||||
export function getDisplayDensity(): number;
|
||||
|
||||
/**
|
||||
* Convert device independent pixels to device pixels - dip to px.
|
||||
* @param value - The pixel to convert.
|
||||
*/
|
||||
export function toDevicePixels(value: dip): px;
|
||||
|
||||
/**
|
||||
* Convert device pixels to device independent pixels - px to dip.
|
||||
* @param value - The pixel to convert.
|
||||
*/
|
||||
export function toDeviceIndependentPixels(value: px): dip;
|
||||
|
||||
/**
|
||||
* Rounds value used in layout.
|
||||
* @param px to round.
|
||||
*/
|
||||
export function round(px: px): px;
|
||||
|
||||
/**
|
||||
* Converts device pixels to device independent pixes and measure the nativeView.
|
||||
* Returns the desired size of the nativeView in device pixels.
|
||||
* @param nativeView the nativeView to measure (UIView or android.view.View)
|
||||
* @param width the available width
|
||||
* @param widthMode width mode - UNSPECIFIED, EXACTLY or AT_MOST
|
||||
* @param height the available hegiht
|
||||
* @param heightMode height mode - UNSPECIFIED, EXACTLY or AT_MOST
|
||||
*/
|
||||
export function measureNativeView(nativeView: any /* UIView or android.view.View */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number };
|
||||
|
||||
/**
|
||||
* Prints user friendly version of the measureSpec.
|
||||
* @param measureSpec the spec to print
|
||||
*/
|
||||
export function measureSpecToString(measureSpec: number): string;
|
36
nativescript-core/utils/layout-helper/layout-helper.ios.ts
Normal file
36
nativescript-core/utils/layout-helper/layout-helper.ios.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { round, MODE_MASK } from "./layout-helper-common";
|
||||
|
||||
export * from "./layout-helper-common";
|
||||
|
||||
let mainScreenScale;
|
||||
|
||||
export function makeMeasureSpec(size: number, mode: number): number {
|
||||
return (Math.round(Math.max(0, size)) & ~MODE_MASK) | (mode & MODE_MASK);
|
||||
}
|
||||
|
||||
export function getDisplayDensity(): number {
|
||||
return mainScreenScale;
|
||||
}
|
||||
|
||||
export function toDevicePixels(value: number): number {
|
||||
return value * mainScreenScale;
|
||||
}
|
||||
|
||||
export function toDeviceIndependentPixels(value: number): number {
|
||||
return value / mainScreenScale;
|
||||
}
|
||||
|
||||
export function measureNativeView(nativeView: any /* UIView */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number } {
|
||||
const view = <UIView>nativeView;
|
||||
const nativeSize = view.sizeThatFits({
|
||||
width: widthMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : toDeviceIndependentPixels(width),
|
||||
height: heightMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : toDeviceIndependentPixels(height)
|
||||
});
|
||||
|
||||
nativeSize.width = round(toDevicePixels(nativeSize.width));
|
||||
nativeSize.height = round(toDevicePixels(nativeSize.height));
|
||||
|
||||
return nativeSize;
|
||||
}
|
||||
|
||||
mainScreenScale = UIScreen.mainScreen.scale;
|
6
nativescript-core/utils/layout-helper/package.json
Normal file
6
nativescript-core/utils/layout-helper/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "layout-helper",
|
||||
"main": "layout-helper",
|
||||
"types": "layout-helper.d.ts",
|
||||
"nativescript": {}
|
||||
}
|
156
nativescript-core/utils/native-helper.android.ts
Normal file
156
nativescript-core/utils/native-helper.android.ts
Normal file
@ -0,0 +1,156 @@
|
||||
import { getNativeApplication, android as androidApp } from "../application";
|
||||
import {
|
||||
messageType as traceMessageType,
|
||||
categories as traceCategories,
|
||||
write as traceWrite
|
||||
} from "../trace";
|
||||
|
||||
// We are using "ad" here to avoid namespace collision with the global android object
|
||||
export module ad {
|
||||
|
||||
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 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) {
|
||||
windowToken = nativeView.getWindowToken();
|
||||
} else if (androidApp.foregroundActivity instanceof androidx.appcompat.app.AppCompatActivity) {
|
||||
const decorView = androidApp.foregroundActivity.getWindow().getDecorView();
|
||||
windowToken = decorView ? decorView.getWindowToken() : null;
|
||||
}
|
||||
|
||||
if (inputManager && windowToken) {
|
||||
inputManager.hideSoftInputFromWindow(windowToken, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export module collections {
|
||||
export function stringArrayToStringSet(str: string[]): java.util.HashSet<string> {
|
||||
const hashSet = new java.util.HashSet<string>();
|
||||
if (str !== undefined) {
|
||||
for (let 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 module 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 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;
|
||||
let field = attr.getField(name);
|
||||
if (field) {
|
||||
colorID = field.getInt(null);
|
||||
}
|
||||
|
||||
if (colorID) {
|
||||
let typedValue = new android.util.TypedValue();
|
||||
context.getTheme().resolveAttribute(colorID, typedValue, true);
|
||||
result = typedValue.data;
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
traceWrite("Cannot get pallete color: " + name, traceCategories.Error, traceMessageType.error);
|
||||
}
|
||||
|
||||
attrCache.set(name, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
159
nativescript-core/utils/native-helper.d.ts
vendored
Normal file
159
nativescript-core/utils/native-helper.d.ts
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Module with android specific utilities.
|
||||
*/
|
||||
export module ad {
|
||||
/**
|
||||
* Gets the native Android application instance.
|
||||
*/
|
||||
export function getApplication(): any /* android.app.Application */;
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
module 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[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility module related to android resources.
|
||||
*/
|
||||
export module 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 id from a given name.
|
||||
* @param name - Name of the resource.
|
||||
*/
|
||||
export function getId(name: string): number;
|
||||
|
||||
/**
|
||||
* [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;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Module with ios specific utilities.
|
||||
*/
|
||||
export module ios {
|
||||
|
||||
// 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.
|
||||
*/
|
||||
module 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: string[]): any;
|
||||
|
||||
/**
|
||||
* Converts NSArray to JavaScript array.
|
||||
* @param a - NSArray to convert.
|
||||
*/
|
||||
export function nsArrayToJSArray(a: any): string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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*/;
|
||||
|
||||
export class UIDocumentInteractionControllerDelegateImpl {}
|
||||
}
|
138
nativescript-core/utils/native-helper.ios.ts
Normal file
138
nativescript-core/utils/native-helper.ios.ts
Normal file
@ -0,0 +1,138 @@
|
||||
import {
|
||||
messageType as traceMessageType,
|
||||
categories as traceCategories,
|
||||
write as traceWrite
|
||||
} from "../trace";
|
||||
|
||||
function isOrientationLandscape(orientation: number) {
|
||||
return orientation === UIDeviceOrientation.LandscapeLeft /* 3 */ ||
|
||||
orientation === UIDeviceOrientation.LandscapeRight /* 4 */;
|
||||
}
|
||||
|
||||
function openFileAtRootModule(filePath: string): boolean {
|
||||
try {
|
||||
const appPath = ios.getCurrentAppPath();
|
||||
const path = filePath.replace("~", appPath);
|
||||
|
||||
const controller = UIDocumentInteractionController.interactionControllerWithURL(NSURL.fileURLWithPath(path));
|
||||
controller.delegate = new ios.UIDocumentInteractionControllerDelegateImpl();
|
||||
|
||||
return controller.presentPreviewAnimated(true);
|
||||
}
|
||||
catch (e) {
|
||||
traceWrite("Error in openFile", traceCategories.Error, traceMessageType.error);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export module ios {
|
||||
// TODO: remove for NativeScript 7.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 module collections {
|
||||
export function jsArrayToNSArray(str: string[]): NSArray<any> {
|
||||
return NSArray.arrayWithArray(<any>str);
|
||||
}
|
||||
|
||||
export function nsArrayToJSArray(a: NSArray<any>): Array<Object> {
|
||||
const arr = [];
|
||||
if (a !== undefined) {
|
||||
let count = a.count;
|
||||
for (let i = 0; i < count; i++) {
|
||||
arr.push(a.objectAtIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if (rootViewController.presentedViewController) {
|
||||
return getVisibleViewController(rootViewController.presentedViewController);
|
||||
}
|
||||
|
||||
if (rootViewController.isKindOfClass(UINavigationController.class())) {
|
||||
return getVisibleViewController((<UINavigationController>rootViewController).visibleViewController);
|
||||
}
|
||||
|
||||
if (rootViewController.isKindOfClass(UITabBarController.class())) {
|
||||
return getVisibleViewController(<UITabBarController>rootViewController);
|
||||
}
|
||||
|
||||
return rootViewController;
|
||||
|
||||
}
|
||||
|
||||
export 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
import * as types from "./types";
|
||||
import { dispatchToMainThread, isMainThread } from "./mainthread-helper";
|
||||
import { sanitizeModuleName } from "../ui/builder/module-name-sanitizer";
|
||||
import * as layout from "./layout-helper";
|
||||
|
||||
export { layout };
|
||||
export * from "./mainthread-helper";
|
||||
|
||||
export const RESOURCE_PREFIX = "res://";
|
||||
@ -39,70 +41,6 @@ export function getModuleName(path: string): string {
|
||||
return sanitizeModuleName(moduleName);
|
||||
}
|
||||
|
||||
export module layoutCommon {
|
||||
const MODE_SHIFT = 30;
|
||||
const MODE_MASK = 0x3 << MODE_SHIFT;
|
||||
|
||||
export const UNSPECIFIED = 0 << MODE_SHIFT;
|
||||
export const EXACTLY = 1 << MODE_SHIFT;
|
||||
export const AT_MOST = 2 << MODE_SHIFT;
|
||||
|
||||
export const MEASURED_HEIGHT_STATE_SHIFT = 0x00000010; /* 16 */
|
||||
export const MEASURED_STATE_TOO_SMALL = 0x01000000;
|
||||
export const MEASURED_STATE_MASK = 0xff000000;
|
||||
export const MEASURED_SIZE_MASK = 0x00ffffff;
|
||||
|
||||
export function getMode(mode: number): string {
|
||||
switch (mode) {
|
||||
case layoutCommon.EXACTLY:
|
||||
return "Exact";
|
||||
case layoutCommon.AT_MOST:
|
||||
return "AtMost";
|
||||
default:
|
||||
return "Unspecified";
|
||||
}
|
||||
}
|
||||
|
||||
export function getMeasureSpecMode(spec: number): number {
|
||||
return (spec & MODE_MASK);
|
||||
}
|
||||
|
||||
export function getMeasureSpecSize(spec: number): number {
|
||||
return (spec & ~MODE_MASK);
|
||||
}
|
||||
|
||||
export function measureSpecToString(measureSpec: number): string {
|
||||
const mode = getMeasureSpecMode(measureSpec);
|
||||
const size = getMeasureSpecSize(measureSpec);
|
||||
|
||||
let text = "MeasureSpec: ";
|
||||
if (mode === UNSPECIFIED) {
|
||||
text += "UNSPECIFIED ";
|
||||
} else if (mode === EXACTLY) {
|
||||
text += "EXACTLY ";
|
||||
} else if (mode === AT_MOST) {
|
||||
text += "AT_MOST ";
|
||||
}
|
||||
|
||||
text += size;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export function round(value: number): number {
|
||||
const res = Math.floor(value + 0.5);
|
||||
if (res !== 0) {
|
||||
return res;
|
||||
} else if (value === 0) {
|
||||
return 0;
|
||||
} else if (value > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
export function isFileOrResourcePath(path: string): boolean {
|
||||
if (!types.isString(path)) {
|
||||
return false;
|
||||
|
@ -1,224 +1,17 @@
|
||||
import { ad } from "./native-helper";
|
||||
import { device } from "../platform";
|
||||
import { FileSystemAccess } from "../file-system/file-system-access";
|
||||
import {
|
||||
write as traceWrite,
|
||||
categories as traceCategories,
|
||||
messageType as traceMessageType,
|
||||
} from "../trace";
|
||||
|
||||
import { layoutCommon } from "./utils-common";
|
||||
|
||||
export { ad };
|
||||
export * from "./utils-common";
|
||||
|
||||
import { getNativeApplication, android as androidApp } from "../application";
|
||||
import { device } from "../platform";
|
||||
import { FileSystemAccess } from "../file-system/file-system-access";
|
||||
|
||||
const MIN_URI_SHARE_RESTRICTED_APK_VERSION = 24;
|
||||
|
||||
export module layout {
|
||||
let density: number;
|
||||
|
||||
// cache the MeasureSpec constants here, to prevent extensive marshaling calls to and from Java
|
||||
// TODO: While this boosts the performance it is error-prone in case Google changes these constants
|
||||
const MODE_SHIFT = 30;
|
||||
const MODE_MASK = 0x3 << MODE_SHIFT;
|
||||
let sdkVersion: number;
|
||||
let useOldMeasureSpec = false;
|
||||
|
||||
export function makeMeasureSpec(size: number, mode: number): number {
|
||||
if (sdkVersion === undefined) {
|
||||
// check whether the old layout is needed
|
||||
sdkVersion = ad.getApplicationContext().getApplicationInfo().targetSdkVersion;
|
||||
useOldMeasureSpec = sdkVersion <= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
|
||||
}
|
||||
|
||||
if (useOldMeasureSpec) {
|
||||
return size + mode;
|
||||
}
|
||||
|
||||
return (size & ~MODE_MASK) | (mode & MODE_MASK);
|
||||
}
|
||||
|
||||
export function getDisplayDensity(): number {
|
||||
if (density === undefined) {
|
||||
density = ad.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
return density;
|
||||
}
|
||||
|
||||
export function toDevicePixels(value: number): number {
|
||||
return value * getDisplayDensity();
|
||||
}
|
||||
|
||||
export function toDeviceIndependentPixels(value: number): number {
|
||||
return value / getDisplayDensity();
|
||||
}
|
||||
|
||||
export function measureNativeView(nativeView: any /* android.view.View */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number } {
|
||||
const view = <android.view.View>nativeView;
|
||||
view.measure(makeMeasureSpec(width, widthMode), makeMeasureSpec(height, heightMode));
|
||||
|
||||
return {
|
||||
width: view.getMeasuredWidth(),
|
||||
height: view.getMeasuredHeight()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(webpack-workflow): Export all methods from layoutCommon
|
||||
// Think of a cleaner way to do that
|
||||
Object.assign(layout, layoutCommon);
|
||||
|
||||
// We are using "ad" here to avoid namespace collision with the global android object
|
||||
export module ad {
|
||||
|
||||
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 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) {
|
||||
windowToken = nativeView.getWindowToken();
|
||||
} else if (androidApp.foregroundActivity instanceof androidx.appcompat.app.AppCompatActivity) {
|
||||
const decorView = androidApp.foregroundActivity.getWindow().getDecorView();
|
||||
windowToken = decorView ? decorView.getWindowToken() : null;
|
||||
}
|
||||
|
||||
if (inputManager && windowToken) {
|
||||
inputManager.hideSoftInputFromWindow(windowToken, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export module collections {
|
||||
export function stringArrayToStringSet(str: string[]): java.util.HashSet<string> {
|
||||
const hashSet = new java.util.HashSet<string>();
|
||||
if (str !== undefined) {
|
||||
for (let 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 module 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 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;
|
||||
let field = attr.getField(name);
|
||||
if (field) {
|
||||
colorID = field.getInt(null);
|
||||
}
|
||||
|
||||
if (colorID) {
|
||||
let typedValue = new android.util.TypedValue();
|
||||
context.getTheme().resolveAttribute(colorID, typedValue, true);
|
||||
result = typedValue.data;
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
traceWrite("Cannot get pallete color: " + name, traceCategories.Error, traceMessageType.error);
|
||||
}
|
||||
|
||||
attrCache.set(name, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function GC() {
|
||||
gc();
|
||||
}
|
||||
|
@ -1,152 +1,20 @@
|
||||
import { ios } from "./native-helper";
|
||||
import {
|
||||
write as traceWrite, categories as traceCategories, messageType as traceMessageType
|
||||
} from "../trace";
|
||||
|
||||
import { layoutCommon } from "./utils-common";
|
||||
export { ios };
|
||||
export * from "./utils-common";
|
||||
|
||||
let mainScreenScale;
|
||||
|
||||
function isOrientationLandscape(orientation: number) {
|
||||
return orientation === UIDeviceOrientation.LandscapeLeft /* 3 */ ||
|
||||
orientation === UIDeviceOrientation.LandscapeRight /* 4 */;
|
||||
}
|
||||
|
||||
export module layout {
|
||||
const MODE_SHIFT = 30;
|
||||
const MODE_MASK = 0x3 << MODE_SHIFT;
|
||||
|
||||
export function makeMeasureSpec(size: number, mode: number): number {
|
||||
return (Math.round(Math.max(0, size)) & ~MODE_MASK) | (mode & MODE_MASK);
|
||||
}
|
||||
|
||||
export function getDisplayDensity(): number {
|
||||
return mainScreenScale;
|
||||
}
|
||||
|
||||
export function toDevicePixels(value: number): number {
|
||||
return value * mainScreenScale;
|
||||
}
|
||||
|
||||
export function toDeviceIndependentPixels(value: number): number {
|
||||
return value / mainScreenScale;
|
||||
}
|
||||
|
||||
export function measureNativeView(nativeView: any /* UIView */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number } {
|
||||
const view = <UIView>nativeView;
|
||||
const nativeSize = view.sizeThatFits({
|
||||
width: widthMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : toDeviceIndependentPixels(width),
|
||||
height: heightMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : toDeviceIndependentPixels(height)
|
||||
});
|
||||
|
||||
nativeSize.width = layoutCommon.round(toDevicePixels(nativeSize.width));
|
||||
nativeSize.height = layoutCommon.round(toDevicePixels(nativeSize.height));
|
||||
|
||||
return nativeSize;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(webpack-workflow): Export all methods from layoutCommon
|
||||
// Think of a cleaner way to do that
|
||||
Object.assign(layout, layoutCommon);
|
||||
|
||||
export module ios {
|
||||
// TODO: remove for NativeScript 7.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 module collections {
|
||||
export function jsArrayToNSArray(str: string[]): NSArray<any> {
|
||||
return NSArray.arrayWithArray(<any>str);
|
||||
}
|
||||
|
||||
export function nsArrayToJSArray(a: NSArray<any>): Array<Object> {
|
||||
const arr = [];
|
||||
if (a !== undefined) {
|
||||
let count = a.count;
|
||||
for (let i = 0; i < count; i++) {
|
||||
arr.push(a.objectAtIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if (rootViewController.presentedViewController) {
|
||||
return getVisibleViewController(rootViewController.presentedViewController);
|
||||
}
|
||||
|
||||
if (rootViewController.isKindOfClass(UINavigationController.class())) {
|
||||
return getVisibleViewController((<UINavigationController>rootViewController).visibleViewController);
|
||||
}
|
||||
|
||||
if (rootViewController.isKindOfClass(UITabBarController.class())) {
|
||||
return getVisibleViewController(<UITabBarController>rootViewController);
|
||||
}
|
||||
|
||||
return rootViewController;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function openFile(filePath: string): boolean {
|
||||
try {
|
||||
const appPath = ios.getCurrentAppPath();
|
||||
const path = filePath.replace("~", appPath);
|
||||
|
||||
const controller = UIDocumentInteractionController.interactionControllerWithURL(NSURL.fileURLWithPath(path));
|
||||
controller.delegate = new UIDocumentInteractionControllerDelegateImpl();
|
||||
controller.delegate = <UIDocumentInteractionControllerDelegate> new ios.UIDocumentInteractionControllerDelegateImpl();
|
||||
|
||||
return controller.presentPreviewAnimated(true);
|
||||
}
|
||||
@ -157,9 +25,6 @@ export function openFile(filePath: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Need this so that we can use this function inside the ios module (avoid name clashing).
|
||||
const openFileAtRootModule = openFile;
|
||||
|
||||
export function GC() {
|
||||
__collect();
|
||||
}
|
||||
@ -183,26 +48,4 @@ export function openUrl(location: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
mainScreenScale = UIScreen.mainScreen.scale;
|
||||
|
Reference in New Issue
Block a user