feat(utils): dismissKeyboard, copyToClipboard, setWindowBackgroundColor, getCurrentActivity and getResource (#10089)

This commit is contained in:
Nathan Walker
2022-11-17 21:05:54 -08:00
committed by GitHub
parent 0226f47f8d
commit 2e1d2c175b
12 changed files with 129 additions and 18 deletions

View File

@ -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 = <Page>args.object;
page.bindingContext = new HelloWorldModel();
if (global.isIOS) {
Utils.ios.setWindowBackgroundColor('blue');
}
}

View File

@ -1,3 +1,3 @@
import { Application } from '@nativescript/core';
import { Application, Utils } from '@nativescript/core';
Application.run({ moduleName: 'app-root' });

View File

@ -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)';

View File

@ -5,13 +5,16 @@
</Page.actionBar>
<StackLayout class="p-10">
<Label text="iPhone by default plays media content in a webview in full screen, meaning it takes over your whole UI. You can toggle this on and off with a cool new property: iosAllowInlineMediaPlayback" textWrap="true" style="color: gray;" class="m-b-10 v-center text-center" />
<Label text="iPhone by default plays media content in a webview in full screen, meaning it takes over your whole UI. You can toggle this on and off with a cool new property: iosAllowInlineMediaPlayback" textWrap="true" style="color: gray;" class="m-b-10 v-center text-center" />
<Label style="color: gray;" textWrap="true" class="m-b-5 text-center" text="This webview plays this youtube content inline." />
<WebView iosAllowInlineMediaPlayback="true" src="https://sphere.presonus.com/video/youtube/QnGX0xrv6Dw" height="200" />
<Label style="color: gray;" textWrap="true" class="m-b-5 text-center" text="This webview plays this youtube content inline." />
<GridLayout rows="200" columns="">
<WebView iosAllowInlineMediaPlayback="true" src="https://www.youtube.com/embed/Mzy1jWxrSiw" height="200" />
</GridLayout>
<Label style="color: gray;" textWrap="true" class="m-b-5 m-t-20 text-center" text="This webview forces media content into fullscreen on iPhone." />
<GridLayout rows="200" columns="">
<WebView src="https://www.youtube.com/embed/Mzy1jWxrSiw" height="200" />
</GridLayout>
<Label style="color: gray;" textWrap="true" class="m-b-5 m-t-20 text-center" text="This webview forces media content into fullscreen on iPhone." />
<WebView src="https://sphere.presonus.com/video/youtube/QnGX0xrv6Dw" height="200" />
</StackLayout>
</StackLayout>
</Page>

View File

@ -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';

View File

@ -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';

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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 = <android.app.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);
}

View File

@ -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
*/

View File

@ -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<T>(_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');