ref: prompt
This commit is contained in:
parent
431a8006ea
commit
c8344e6037
@ -23,7 +23,7 @@ export const startAndDecrypt = async (retry?: boolean, passwordPrompt?: Password
|
||||
password = await passwordPrompt();
|
||||
} else {
|
||||
do {
|
||||
password = await prompt((retry && loc._.bad_password) || loc._.enter_password, loc._.storage_is_encrypted, false);
|
||||
password = await prompt((retry && loc._.bad_password) || loc._.enter_password, loc._.storage_is_encrypted, { cancelable: false });
|
||||
} while (!password);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,15 +2,18 @@ import { Platform } from 'react-native';
|
||||
import prompt from 'react-native-prompt-android';
|
||||
import loc from '../loc';
|
||||
|
||||
export default (
|
||||
title: string,
|
||||
text: string,
|
||||
isCancelable = true,
|
||||
type: PromptType | PromptTypeIOS | PromptTypeAndroid = 'secure-text',
|
||||
isOKDestructive = false,
|
||||
continueButtonText = loc._.ok,
|
||||
defaultInputValue?: string,
|
||||
): Promise<string> => {
|
||||
type PromptHelperOptions = {
|
||||
cancelable?: boolean;
|
||||
type?: PromptType | PromptTypeIOS | PromptTypeAndroid;
|
||||
destructive?: boolean; // applies only to the cancelable (two-button) layout
|
||||
continueButtonText?: string;
|
||||
defaultValue?: string;
|
||||
};
|
||||
|
||||
export default (title: string, text: string, options: PromptHelperOptions = {}): Promise<string> => {
|
||||
const { cancelable = true, destructive = false, continueButtonText = loc._.ok, defaultValue } = options;
|
||||
let { type = 'secure-text' } = options;
|
||||
|
||||
const keyboardType = type === 'numeric' ? 'numeric' : 'default';
|
||||
|
||||
if (Platform.OS === 'ios' && type === 'numeric') {
|
||||
@ -19,7 +22,7 @@ export default (
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const buttons: Array<PromptButton> = isCancelable
|
||||
const buttons: Array<PromptButton> = cancelable
|
||||
? [
|
||||
{
|
||||
text: loc._.cancel,
|
||||
@ -34,7 +37,7 @@ export default (
|
||||
console.log('OK Pressed');
|
||||
resolve(password);
|
||||
},
|
||||
style: isOKDestructive ? 'destructive' : 'default',
|
||||
style: destructive ? 'destructive' : 'default',
|
||||
},
|
||||
]
|
||||
: [
|
||||
@ -47,13 +50,12 @@ export default (
|
||||
},
|
||||
];
|
||||
|
||||
const message = defaultInputValue !== undefined ? '' : text;
|
||||
const message = defaultValue !== undefined ? '' : text;
|
||||
prompt(title, message, buttons, {
|
||||
type,
|
||||
cancelable: isCancelable,
|
||||
// @ts-ignore suppressed because its supported only on ios and is absent from type definitions
|
||||
cancelable,
|
||||
keyboardType,
|
||||
...(defaultInputValue !== undefined && { defaultValue: defaultInputValue }),
|
||||
...(defaultValue !== undefined && { defaultValue }),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@ -140,7 +140,7 @@ const LnurlPay: React.FC = () => {
|
||||
try {
|
||||
let comment: string | undefined;
|
||||
if (_LN.getCommentAllowed()) {
|
||||
comment = await prompt('Comment', '', false, 'plain-text');
|
||||
comment = await prompt('Comment', '', { cancelable: false, type: 'plain-text' });
|
||||
}
|
||||
|
||||
const bolt11payload = await _LN.requestBolt11FromLnurlPayService(amountSats, comment);
|
||||
|
||||
@ -677,7 +677,7 @@ const TransactionStatus: React.FC = () => {
|
||||
const handleNotePress = useCallback(async () => {
|
||||
const currentMemo = txMetadata[tx.hash]?.memo || '';
|
||||
try {
|
||||
const newMemo = await prompt(loc.send.details_note_placeholder, '', true, 'plain-text', false, undefined, currentMemo);
|
||||
const newMemo = await prompt(loc.send.details_note_placeholder, '', { type: 'plain-text', defaultValue: currentMemo });
|
||||
if (newMemo !== undefined) {
|
||||
txMetadata[tx.hash] = { memo: newMemo };
|
||||
await saveToDisk();
|
||||
|
||||
@ -134,7 +134,7 @@ export default function PaymentCodesList() {
|
||||
break;
|
||||
}
|
||||
case String(Actions.rename): {
|
||||
const newName = await prompt(loc.bip47.rename, loc.bip47.provide_name, true, 'plain-text');
|
||||
const newName = await prompt(loc.bip47.rename, loc.bip47.provide_name, { type: 'plain-text' });
|
||||
if (!newName) return;
|
||||
|
||||
counterpartyMetadata[pc] = { label: newName };
|
||||
@ -245,7 +245,7 @@ export default function PaymentCodesList() {
|
||||
|
||||
const onAddContactPress = async () => {
|
||||
try {
|
||||
const newPc = await prompt(loc.bip47.add_contact, loc.bip47.provide_payment_code, true, 'plain-text');
|
||||
const newPc = await prompt(loc.bip47.add_contact, loc.bip47.provide_payment_code, { type: 'plain-text' });
|
||||
if (!newPc) return;
|
||||
|
||||
await _addContact(newPc);
|
||||
|
||||
@ -74,6 +74,7 @@ const WalletDetails: React.FC = () => {
|
||||
|
||||
const [masterFingerprint, setMasterFingerprint] = useState<string | undefined>();
|
||||
const [arkAddress, setArkAddress] = useState<string>('');
|
||||
const [walletName, setWalletName] = useState<string>(wallet.getLabel());
|
||||
const walletTransactionsLength = useMemo<number>(() => wallet.getTransactions().length, [wallet]);
|
||||
const [coinControlStats, setCoinControlStats] = useState(() => getCoinControlStats(wallet));
|
||||
|
||||
@ -157,10 +158,7 @@ const WalletDetails: React.FC = () => {
|
||||
const walletBalanceConfirmation = await prompt(
|
||||
loc.wallets.details_delete_wallet,
|
||||
loc.formatString(loc.wallets.details_del_wb_q, { balance }),
|
||||
true,
|
||||
'numeric',
|
||||
true,
|
||||
loc.wallets.details_delete,
|
||||
{ type: 'numeric', destructive: true, continueButtonText: loc.wallets.details_delete },
|
||||
);
|
||||
// Remove any non-numeric characters before comparison
|
||||
const cleanedConfirmation = (walletBalanceConfirmation || '').replace(/[^0-9]/g, '');
|
||||
@ -485,15 +483,26 @@ const WalletDetails: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleEditWalletName = useCallback(async () => {
|
||||
let newName: string;
|
||||
try {
|
||||
const newName = await prompt(loc.wallets.add_wallet_name, '', true, 'plain-text', false, undefined, wallet.getLabel());
|
||||
const trimmed = newName.trim();
|
||||
if (trimmed.length === 0) return;
|
||||
if (wallet.getLabel() === trimmed) return;
|
||||
wallet.setLabel(trimmed);
|
||||
await saveToDisk();
|
||||
newName = await prompt(loc.wallets.add_wallet_name, '', { type: 'plain-text', defaultValue: wallet.getLabel() });
|
||||
} catch (_) {
|
||||
// User cancelled
|
||||
return;
|
||||
}
|
||||
const trimmed = newName.trim();
|
||||
if (trimmed.length === 0) return;
|
||||
const previousLabel = wallet.getLabel();
|
||||
if (previousLabel === trimmed) return;
|
||||
wallet.setLabel(trimmed);
|
||||
setWalletName(trimmed);
|
||||
try {
|
||||
await saveToDisk();
|
||||
} catch (error: unknown) {
|
||||
wallet.setLabel(previousLabel);
|
||||
setWalletName(previousLabel);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
presentAlert({ message: error instanceof Error ? error.message : String(error) });
|
||||
}
|
||||
}, [wallet, saveToDisk]);
|
||||
|
||||
@ -519,7 +528,7 @@ const WalletDetails: React.FC = () => {
|
||||
ellipsizeMode="tail"
|
||||
testID="WalletNameDisplay"
|
||||
>
|
||||
{wallet.getLabel()}
|
||||
{walletName}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
style={[styles.editButton, stylesHook.editButton]}
|
||||
|
||||
@ -286,7 +286,7 @@ const WalletsAddMultisigStep2 = () => {
|
||||
// do nothing, it's already set
|
||||
} else {
|
||||
try {
|
||||
fp = await prompt(loc.multisig.input_fp, loc.multisig.input_fp_explain, true, 'plain-text');
|
||||
fp = await prompt(loc.multisig.input_fp, loc.multisig.input_fp_explain, { type: 'plain-text' });
|
||||
fp = (fp + '').toUpperCase();
|
||||
if (!MultisigHDWallet.isFpValid(fp)) fp = '00000000';
|
||||
} catch (e) {
|
||||
@ -297,12 +297,9 @@ const WalletsAddMultisigStep2 = () => {
|
||||
// do nothing, it's already set
|
||||
} else {
|
||||
try {
|
||||
path = await prompt(
|
||||
loc.multisig.input_path,
|
||||
loc.formatString(loc.multisig.input_path_explain, { default: getPath() }),
|
||||
true,
|
||||
'plain-text',
|
||||
);
|
||||
path = await prompt(loc.multisig.input_path, loc.formatString(loc.multisig.input_path_explain, { default: getPath() }), {
|
||||
type: 'plain-text',
|
||||
});
|
||||
if (!MultisigHDWallet.isPathValid(path)) path = getPath();
|
||||
} catch {
|
||||
return setIsLoading(false);
|
||||
|
||||
@ -270,15 +270,10 @@ describe('TransactionStatus regression', () => {
|
||||
expect(mockPrompt).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// 7th argument is defaultInputValue: current memo should be in the input field, not in the message
|
||||
expect(mockPrompt).toHaveBeenCalledWith(
|
||||
'Note to Self',
|
||||
'', // message empty so content is not in alert body
|
||||
true,
|
||||
'plain-text',
|
||||
false,
|
||||
undefined,
|
||||
existingMemo, // defaultInputValue: pre-fill input for easy editing
|
||||
{ type: 'plain-text', defaultValue: existingMemo }, // defaultValue: pre-fill input for easy editing
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
72
typings/react-native-prompt-android.d.ts
vendored
72
typings/react-native-prompt-android.d.ts
vendored
@ -1,57 +1,27 @@
|
||||
// Type definitions for react-native-prompt-android 0.3.1
|
||||
// Project: https://github.com/shimohq/react-native-prompt-android
|
||||
// Definitions by: Krystof Celba <https://github.com/krystofcelba>
|
||||
// TypeScript Version: 2.6.1
|
||||
// Supplemental types for `react-native-prompt-android`.
|
||||
// The package ships its own `index.d.ts`; this file only adds the type aliases
|
||||
// used unqualified across the app, plus a `keyboardType` augmentation that is
|
||||
// absent from the upstream definitions.
|
||||
|
||||
type PromptButton = {
|
||||
text?: string;
|
||||
onPress?: (message: string) => void;
|
||||
import type { KeyboardTypeOptions } from 'react-native';
|
||||
|
||||
/** @platform ios */
|
||||
style?: 'default' | 'cancel' | 'destructive';
|
||||
};
|
||||
declare global {
|
||||
type PromptButton = {
|
||||
text?: string;
|
||||
onPress?: (message: string) => void;
|
||||
|
||||
type PromptType = 'default' | 'plain-text' | 'secure-text';
|
||||
type PromptTypeIOS = 'login-password';
|
||||
type PromptTypeAndroid = 'numeric' | 'email-address' | 'phone-pad';
|
||||
/** @platform ios */
|
||||
style?: 'default' | 'cancel' | 'destructive';
|
||||
};
|
||||
|
||||
type PromptStyleAndroid = 'default' | 'shimo';
|
||||
|
||||
interface PromptOptions {
|
||||
/**
|
||||
* * Cross platform:
|
||||
*
|
||||
* - `'default'`
|
||||
* - `'plain-text'`
|
||||
* - `'secure-text'`
|
||||
*
|
||||
* * iOS only:
|
||||
*
|
||||
* - `'login-password'`
|
||||
*
|
||||
* * Android only:
|
||||
*
|
||||
* - `'numeric'`
|
||||
* - `'email-address'`
|
||||
* - `'phone-pad'`
|
||||
*/
|
||||
type?: PromptType | PromptTypeIOS | PromptTypeAndroid;
|
||||
|
||||
defaultValue?: string;
|
||||
|
||||
/** @platform android */
|
||||
placeholder?: string;
|
||||
|
||||
/** @platform android */
|
||||
cancelable?: boolean;
|
||||
|
||||
/** @platform android */
|
||||
style?: PromptStyleAndroid;
|
||||
type PromptType = 'default' | 'plain-text' | 'secure-text';
|
||||
type PromptTypeIOS = 'login-password';
|
||||
type PromptTypeAndroid = 'numeric' | 'email-address' | 'phone-pad';
|
||||
}
|
||||
|
||||
declare function prompt(
|
||||
title?: string,
|
||||
message?: string,
|
||||
callbackOrButtons?: ((value: string) => void) | Array<PromptButton>,
|
||||
options?: PromptOptions,
|
||||
): void;
|
||||
// `keyboardType` is supported by the native prompt but is absent from the upstream type definitions.
|
||||
declare module 'react-native-prompt-android' {
|
||||
interface PromptOptions {
|
||||
keyboardType?: KeyboardTypeOptions;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user