diff --git a/README.md b/README.md index bb70d12..dc070e1 100644 --- a/README.md +++ b/README.md @@ -1257,6 +1257,70 @@ Writes the given text to the clipboard writeTextToClipboard: (text: string) => Promise; ``` +### showLoadingOverlay / hideLoadingOverlay + +App version >=24.10 + +Shows a loading overlay screen while a task is being performed. You can control +when to hide it with the `hideLoadingOverlay` method. + +```ts +showLoadingOverlay: ({ + /** + * Whether the in animation is enabled (false by default) + */ + inAnimation?: boolean; + /** + * Whether the out animation is enabled (false by default) + */ + outAnimation?: boolean; + /** + * Minimum duration of the loop animation in milliseconds (0 by default) + */ + minimumLoopDurationMs?: number; + /** + * whether the loop animation should be stopped immediately or not (true by default) + */ + stopAnimationCycle?: boolean; + /** + * Whether the background animation is enabled (false by default) + */ + backgroundAnimation?: boolean; + /** + * List of description texts to be shown one after the other + */ + descriptions?: Array; + /** + * Duration of each description in milliseconds (3000 by default) + */ + descriptionDurationMs?: number; + /** + * After this timeout loading screen would be hidden automatically (20000 by default) + */ + timeoutMs?: number; + /** + * (Only Android) If true, after loading screen has been hidden, if user presses android back button, webview window will close (true by default) + */ + closeOnBackButtonPressAfterFinish?: boolean; +}) => Promise; + +hideLoadingOverlay: () => Promise; +``` + +#### Example + +```ts +await showLoadingOverlay({ + inAnimation: true, + outAnimation: true, + stopAnimationCycle: false, + descriptions: ['Loading...', 'Please wait...'], + descriptionDurationMs: 3000, +}); +await doExpensiveTask(); +await hideLoadingOverlay(); +``` + ## Error handling If an uncontrolled error occurs, promise will be rejected with an error object: diff --git a/index.ts b/index.ts index 6779c39..9a8d4db 100644 --- a/index.ts +++ b/index.ts @@ -47,6 +47,8 @@ export { onNavigationBarIconClicked, triggerPinOrBiometricAuthentication, focusNavbar, + showLoadingOverlay, + hideLoadingOverlay, } from './src/utils'; export type {ShareOptions, NavigationBarIcon} from './src/utils'; diff --git a/src/__tests__/utils-test.ts b/src/__tests__/utils-test.ts index 5405617..cae41fb 100644 --- a/src/__tests__/utils-test.ts +++ b/src/__tests__/utils-test.ts @@ -19,6 +19,8 @@ import { getAppMetadata, getNetworkConnectionInfo, getTopazValues, + hideLoadingOverlay, + showLoadingOverlay, } from '../utils'; const ANY_STRING = 'any-string'; @@ -651,3 +653,53 @@ test('get Topaz values', async () => { expect(res).toEqual({syncId}); }); }); + +test('showLoadingOverlay', async () => { + createFakeAndroidPostMessage({ + checkMessage: (message) => { + expect(message.type).toBe('SHOW_LOADING_OVERLAY'); + expect(message.payload).toEqual({ + inAnimation: true, + outAnimation: true, + stopAnimationCycle: false, + timeoutMs: 30000, + descriptions: [ + 'Loading your data', + 'Please wait', + 'We are almost there', + ], + }); + }, + getResponse: (message) => ({ + type: message.type, + id: message.id, + }), + }); + + await showLoadingOverlay({ + inAnimation: true, + outAnimation: true, + stopAnimationCycle: false, + timeoutMs: 30000, + descriptions: [ + 'Loading your data', + 'Please wait', + 'We are almost there', + ], + }); +}); + +test('hideLoadingOverlay', async () => { + createFakeAndroidPostMessage({ + checkMessage: (message) => { + expect(message.type).toBe('HIDE_LOADING_OVERLAY'); + expect(message.payload).toBeUndefined(); + }, + getResponse: (message) => ({ + type: message.type, + id: message.id, + }), + }); + + await hideLoadingOverlay(); +}); diff --git a/src/post-message.ts b/src/post-message.ts index 8932c91..885a494 100644 --- a/src/post-message.ts +++ b/src/post-message.ts @@ -361,6 +361,16 @@ export type ResponsesFromNativeApp = { id: string; payload: void; }; + SHOW_LOADING_OVERLAY: { + type: 'SHOW_LOADING_OVERLAY'; + id: string; + payload: void; + }; + HIDE_LOADING_OVERLAY: { + type: 'HIDE_LOADING_OVERLAY'; + id: string; + payload: void; + }; }; export type NativeAppResponsePayload< diff --git a/src/utils.ts b/src/utils.ts index 5e64872..fcaa1b9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -329,3 +329,46 @@ export const triggerPinOrBiometricAuthentication = ( export const focusNavbar = (): Promise<{focused: boolean}> => postMessageToNativeApp({type: 'FOCUS_NAVBAR'}); + +export const showLoadingOverlay = (payload: { + /** + * Whether the in animation is enabled (false by default) + */ + inAnimation?: boolean; + /** + * Whether the out animation is enabled (false by default) + */ + outAnimation?: boolean; + /** + * Minimum duration of the loop animation in milliseconds (0 by default) + */ + minimumLoopDurationMs?: number; + /** + * whether the loop animation should be stopped immediately or not (true by default) + */ + stopAnimationCycle?: boolean; + /** + * Whether the background animation is enabled (false by default) + */ + backgroundAnimation?: boolean; + /** + * List of description texts to be shown one after the other + */ + descriptions?: Array; + /** + * Duration of each description in milliseconds (3000 by default) + */ + descriptionDurationMs?: number; + /** + * After this timeout loading screen would be hidden automatically (20000 by default) + */ + timeoutMs?: number; + /** + * (Only Android) If true, after loading screen has been hidden, if user presses android back button, webview window will close (true by default) + */ + closeOnBackButtonPressAfterFinish?: boolean; +}): Promise => + postMessageToNativeApp({type: 'SHOW_LOADING_OVERLAY', payload}); + +export const hideLoadingOverlay = (): Promise => + postMessageToNativeApp({type: 'HIDE_LOADING_OVERLAY'});