diff --git a/apps/toolbox/src/main-page.ts b/apps/toolbox/src/main-page.ts
index c2e8a7d5a..fec18a3ba 100644
--- a/apps/toolbox/src/main-page.ts
+++ b/apps/toolbox/src/main-page.ts
@@ -1,7 +1,11 @@
-import { EventData, Page } from '@nativescript/core';
+import { EventData, Page, Utils } from '@nativescript/core';
import { HelloWorldModel } from './main-view-model';
export function navigatingTo(args: EventData) {
const page = args.object;
page.bindingContext = new HelloWorldModel();
+
+ if (global.isIOS) {
+ Utils.ios.setWindowBackgroundColor('blue');
+ }
}
diff --git a/apps/toolbox/src/main.ts b/apps/toolbox/src/main.ts
index a4c5c529a..fba0a27ac 100644
--- a/apps/toolbox/src/main.ts
+++ b/apps/toolbox/src/main.ts
@@ -1,3 +1,3 @@
-import { Application } from '@nativescript/core';
+import { Application, Utils } from '@nativescript/core';
Application.run({ moduleName: 'app-root' });
diff --git a/apps/toolbox/src/pages/box-shadow.ts b/apps/toolbox/src/pages/box-shadow.ts
index f269b3a2b..5de8dd7b1 100644
--- a/apps/toolbox/src/pages/box-shadow.ts
+++ b/apps/toolbox/src/pages/box-shadow.ts
@@ -10,7 +10,7 @@ export class BoxShadowModel extends Observable {
private _selectedBackgroundType: string;
private _selectedBorderType: string;
private _selectedAnimation: string;
- private _boxShadow: string = '0 10 15 -3 rgba(200, 0, 0, 0.4)';
+ private _boxShadow: string = '0 0 2 2 rgba(200, 0, 0, 0.4)';
// private _boxShadow: string = '5 5 1 1 rgba(255, 0, 0, .9)';
// private _boxShadow: string = '5 5 5 10 rgba(255, 0, 0, .9)';
diff --git a/apps/toolbox/src/pages/webview.xml b/apps/toolbox/src/pages/webview.xml
index 73f5b8f60..4ff23f3a6 100644
--- a/apps/toolbox/src/pages/webview.xml
+++ b/apps/toolbox/src/pages/webview.xml
@@ -5,13 +5,16 @@
-
+
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
diff --git a/packages/core/index.d.ts b/packages/core/index.d.ts
index 3c75a31ad..c92f5b7be 100644
--- a/packages/core/index.d.ts
+++ b/packages/core/index.d.ts
@@ -105,7 +105,7 @@ export type { InstrumentationMode, TimerInfo } from './profiling';
export { encoding } from './text';
export * from './trace';
export * from './ui';
-import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString, dismissSoftInput, queueMacrotask, queueGC, throttle, debounce, dataSerialize, dataDeserialize } from './utils';
+import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString, dismissSoftInput, dismissKeyboard, queueMacrotask, queueGC, throttle, debounce, dataSerialize, dataDeserialize, copyToClipboard } from './utils';
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback, numberHasDecimals, numberIs64Bit } from './utils/types';
export declare const Utils: {
GC: typeof GC;
@@ -158,5 +158,7 @@ export declare const Utils: {
toUIString: typeof toUIString;
verifyCallback: typeof verifyCallback;
dismissSoftInput: typeof dismissSoftInput;
+ dismissKeyboard: typeof dismissKeyboard;
+ copyToClipboard: typeof copyToClipboard;
};
export { XmlParser, ParserEventType, ParserEvent } from './xml';
diff --git a/packages/core/index.ts b/packages/core/index.ts
index bc57df100..4d536133e 100644
--- a/packages/core/index.ts
+++ b/packages/core/index.ts
@@ -137,7 +137,7 @@ export * from './trace';
export * from './ui';
-import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, queueMacrotask, queueGC, debounce, throttle, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString, dismissSoftInput, dataDeserialize, dataSerialize } from './utils';
+import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, queueMacrotask, queueGC, debounce, throttle, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString, dismissSoftInput, dismissKeyboard, dataDeserialize, dataSerialize, copyToClipboard } from './utils';
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback, numberHasDecimals, numberIs64Bit } from './utils/types';
export const Utils = {
@@ -194,6 +194,8 @@ export const Utils = {
toUIString,
verifyCallback,
dismissSoftInput,
+ dismissKeyboard,
+ copyToClipboard,
};
export { XmlParser, ParserEventType, ParserEvent } from './xml';
diff --git a/packages/core/utils/index.android.ts b/packages/core/utils/index.android.ts
index b4a28b6ed..919bcf30c 100644
--- a/packages/core/utils/index.android.ts
+++ b/packages/core/utils/index.android.ts
@@ -1,4 +1,5 @@
import { ad } from './native-helper';
+import { android as androidApp } from '../application';
import { SDK_VERSION } from '../utils';
import { FileSystemAccess } from '../file-system/file-system-access';
import { Trace } from '../trace';
@@ -170,3 +171,26 @@ export function isRealDevice(): boolean {
export function dismissSoftInput(nativeView?: any): void {
ad.dismissSoftInput(nativeView);
}
+
+export function dismissKeyboard() {
+ dismissSoftInput();
+
+ const activity = ad.getCurrentActivity();
+ if (activity) {
+ const focus = activity.getCurrentFocus();
+
+ if (focus) {
+ focus.clearFocus();
+ }
+ }
+}
+
+export function copyToClipboard(value: string) {
+ try {
+ const clipboard = ad.getApplicationContext().getSystemService(android.content.Context.CLIPBOARD_SERVICE);
+ const clip = android.content.ClipData.newPlainText('Clipboard value', value);
+ clipboard.setPrimaryClip(clip);
+ } catch (err) {
+ console.log(err);
+ }
+}
diff --git a/packages/core/utils/index.d.ts b/packages/core/utils/index.d.ts
index 425f4fcb9..7b17bf2a4 100644
--- a/packages/core/utils/index.d.ts
+++ b/packages/core/utils/index.d.ts
@@ -321,3 +321,13 @@ export function isRealDevice(): boolean;
* Hides the soft input method, usually a soft keyboard.
*/
export function dismissSoftInput(nativeView?: any): void;
+
+/**
+ * Dismiss any keyboard visible on the screen.
+ */
+export function dismissKeyboard(): void;
+
+/**
+ * Copy value to device clipboard.
+ */
+export function copyToClipboard(value: string): void;
diff --git a/packages/core/utils/index.ios.ts b/packages/core/utils/index.ios.ts
index 70c0f18bc..5044fbc1b 100644
--- a/packages/core/utils/index.ios.ts
+++ b/packages/core/utils/index.ios.ts
@@ -55,3 +55,15 @@ export function dismissSoftInput(nativeView?: UIView): void {
}
UIApplication.sharedApplication.sendActionToFromForEvent('resignFirstResponder', null, null, null);
}
+
+export function dismissKeyboard() {
+ dismissSoftInput();
+}
+
+export function copyToClipboard(value: string) {
+ try {
+ UIPasteboard.generalPasteboard.setValueForPasteboardType(value, kUTTypePlainText);
+ } catch (err) {
+ console.log(err);
+ }
+}
diff --git a/packages/core/utils/native-helper.android.ts b/packages/core/utils/native-helper.android.ts
index 978793ce9..48dadb2c3 100644
--- a/packages/core/utils/native-helper.android.ts
+++ b/packages/core/utils/native-helper.android.ts
@@ -152,6 +152,12 @@ export namespace ad {
return applicationContext;
}
+ export function getCurrentActivity() {
+ if (!androidApp) {
+ return null;
+ }
+ return androidApp.foregroundActivity || androidApp.startActivity;
+ }
export function getApplication() {
if (!application) {
application = getNativeApplication();
@@ -199,8 +205,8 @@ export namespace ad {
return;
}
windowToken = nativeView.getWindowToken();
- } else if (androidApp.foregroundActivity instanceof androidx.appcompat.app.AppCompatActivity) {
- const decorView = androidApp.foregroundActivity.getWindow().getDecorView();
+ } else if (getCurrentActivity() instanceof androidx.appcompat.app.AppCompatActivity) {
+ const decorView = getCurrentActivity().getWindow().getDecorView();
if (decorView) {
windowToken = decorView.getWindowToken();
decorView.requestFocus();
@@ -259,6 +265,9 @@ export namespace ad {
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);
}
diff --git a/packages/core/utils/native-helper.d.ts b/packages/core/utils/native-helper.d.ts
index e21f9f131..11ec7d9e4 100644
--- a/packages/core/utils/native-helper.d.ts
+++ b/packages/core/utils/native-helper.d.ts
@@ -18,6 +18,10 @@ export namespace ad {
*/
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.
*/
@@ -82,6 +86,15 @@ export namespace ad {
*/
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;
+
/**
* [Obsolete - please use getPaletteColor] Gets a color from current theme.
* @param name - Name of the color
@@ -137,6 +150,18 @@ export namespace iOSNativeHelper {
*/
export function getRootViewController(): any; /* UIViewController */
+ /**
+ * 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;
+
/**
* Data serialize and deserialize helpers
*/
diff --git a/packages/core/utils/native-helper.ios.ts b/packages/core/utils/native-helper.ios.ts
index b6d70fc87..2169f070f 100644
--- a/packages/core/utils/native-helper.ios.ts
+++ b/packages/core/utils/native-helper.ios.ts
@@ -1,3 +1,4 @@
+import { Color } from '../color';
import { Trace } from '../trace';
import { getClass, isNullOrUndefined, numberHasDecimals, numberIs64Bit } from './types';
@@ -108,7 +109,7 @@ export function dataSerialize(data: any, wrapPrimitives: boolean = false) {
}
export namespace iOSNativeHelper {
- // TODO: remove for NativeScript 7.0
+ // 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') {
@@ -137,15 +138,34 @@ export namespace iOSNativeHelper {
}
export function getRootViewController(): UIViewController {
- const app = UIApplication.sharedApplication;
- const win = app.keyWindow || (app.windows && app.windows.count > 0 && app.windows.objectAtIndex(0));
- let vc = win.rootViewController;
+ 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');