Merge branch 'master' into priceintent

This commit is contained in:
Marcos Rodriguez Vélez 2024-10-27 23:17:46 -04:00 committed by GitHub
commit e390b9beab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 373 additions and 334 deletions

View File

@ -341,4 +341,4 @@ export {
satoshiToLocalCurrency,
setPreferredCurrency,
updateExchangeRate,
};
};

View File

@ -1,8 +1,10 @@
import React from 'react';
import React, { useCallback } from 'react';
import { Keyboard, StyleSheet, TextInput, View } from 'react-native';
import loc from '../loc';
import { AddressInputScanButton } from './AddressInputScanButton';
import { useTheme } from './themes';
import DeeplinkSchemaMatch from '../class/deeplink-schema-match';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../blue_modules/hapticFeedback';
interface AddressInputProps {
isLoading?: boolean;
@ -60,7 +62,20 @@ const AddressInput = ({
},
});
const validateAddressWithFeedback = useCallback((value: string) => {
const isBitcoinAddress = DeeplinkSchemaMatch.isBitcoinAddress(value);
const isLightningInvoice = DeeplinkSchemaMatch.isLightningInvoice(value);
const isValid = isBitcoinAddress || isLightningInvoice;
triggerHapticFeedback(isValid ? HapticFeedbackTypes.NotificationSuccess : HapticFeedbackTypes.NotificationError);
return {
isValid,
type: isBitcoinAddress ? 'bitcoin' : isLightningInvoice ? 'lightning' : 'invalid',
};
}, []);
const onBlurEditing = () => {
validateAddressWithFeedback(address);
onBlur();
Keyboard.dismiss();
};
@ -106,11 +121,12 @@ const styles = StyleSheet.create({
height: 44,
alignItems: 'center',
marginVertical: 8,
marginHorizontal: 18,
borderRadius: 4,
},
input: {
flex: 1,
marginHorizontal: 8,
paddingHorizontal: 8,
minHeight: 33,
},
});

View File

@ -1,19 +1,35 @@
import React from 'react';
import { Pressable, Platform } from 'react-native';
import ToolTipMenu from './TooltipMenu';
import { useTheme } from './themes';
import { Icon } from '@rneui/themed';
import { Platform } from 'react-native';
import { Action } from './types';
interface HeaderMenuButtonProps {
onPressMenuItem: (id: string) => void;
actions: Action[];
actions?: Action[] | Action[][];
disabled?: boolean;
}
const HeaderMenuButton: React.FC<HeaderMenuButtonProps> = ({ onPressMenuItem, actions, disabled }) => {
const { colors } = useTheme();
const styleProps = Platform.OS === 'android' ? { iconStyle: { transform: [{ rotate: '90deg' }] } } : {};
if (!actions || actions.length === 0) {
return (
<Pressable
testID="HeaderMenuButton"
disabled={disabled}
android_ripple={{ color: colors.lightButton }}
style={({ pressed }) => [{ opacity: pressed ? 0.5 : 1 }]}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} {...styleProps} />
</Pressable>
);
}
const menuActions = Array.isArray(actions[0]) ? (actions as Action[][]) : (actions as Action[]);
return (
<ToolTipMenu
testID="HeaderMenuButton"
@ -21,7 +37,7 @@ const HeaderMenuButton: React.FC<HeaderMenuButtonProps> = ({ onPressMenuItem, ac
isButton
isMenuPrimaryAction
onPressMenuItem={onPressMenuItem}
actions={actions}
actions={menuActions}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} {...styleProps} />
</ToolTipMenu>

View File

@ -1,6 +1,5 @@
import React, { useMemo } from 'react';
import React, { useMemo, useCallback } from 'react';
import Clipboard from '@react-native-clipboard/clipboard';
import { useNavigation } from '@react-navigation/native';
import { StyleSheet, Text, View } from 'react-native';
import { ListItem } from '@rneui/themed';
import Share from 'react-native-share';
@ -12,15 +11,15 @@ import { BitcoinUnit } from '../../models/bitcoinUnits';
import presentAlert from '../Alert';
import QRCodeComponent from '../QRCodeComponent';
import { useTheme } from '../themes';
import { Action } from '../types';
import { AddressTypeBadge } from './AddressTypeBadge';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
import { useStorage } from '../../hooks/context/useStorage';
import ToolTipMenu from '../TooltipMenu';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
interface AddressItemProps {
// todo: fix `any` after addresses.js is converted to the church of holy typescript
item: any;
balanceUnit: BitcoinUnit;
walletID: string;
@ -55,9 +54,9 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
},
});
const { navigate } = useNavigation<NavigationProps>();
const { navigate } = useExtendedNavigation<NavigationProps>();
const navigateToReceive = () => {
const navigateToReceive = useCallback(() => {
navigate('ReceiveDetailsRoot', {
screen: 'ReceiveDetails',
params: {
@ -65,9 +64,9 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
address: item.address,
},
});
};
}, [navigate, walletID, item.address]);
const navigateToSignVerify = () => {
const navigateToSignVerify = useCallback(() => {
navigate('SignVerifyRoot', {
screen: 'SignVerify',
params: {
@ -75,21 +74,36 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
address: item.address,
},
});
};
}, [navigate, walletID, item.address]);
const menuActions = useMemo(() => getAvailableActions({ allowSignVerifyMessage }), [allowSignVerifyMessage]);
const menuActions = useMemo(
() =>
[
CommonToolTipActions.CopyTXID,
CommonToolTipActions.Share,
{
...CommonToolTipActions.SignVerify,
hidden: !allowSignVerifyMessage,
},
{
...CommonToolTipActions.ExportPrivateKey,
hidden: !allowSignVerifyMessage,
},
].filter(action => !action.hidden),
[allowSignVerifyMessage],
);
const balance = formatBalance(item.balance, balanceUnit, true);
const handleCopyPress = () => {
const handleCopyPress = useCallback(() => {
Clipboard.setString(item.address);
};
}, [item.address]);
const handleSharePress = () => {
const handleSharePress = useCallback(() => {
Share.open({ message: item.address }).catch(error => console.log(error));
};
}, [item.address]);
const handleCopyPrivkeyPress = () => {
const handleCopyPrivkeyPress = useCallback(() => {
const wallet = wallets.find(w => w.getID() === walletID);
if (!wallet) {
presentAlert({ message: 'Internal error: cant find wallet' });
@ -107,86 +121,60 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
} catch (error: any) {
presentAlert({ message: error.message });
}
};
}, [wallets, walletID, item.address]);
const onToolTipPress = async (id: string) => {
if (id === actionKeys.CopyToClipboard) {
handleCopyPress();
} else if (id === actionKeys.Share) {
handleSharePress();
} else if (id === actionKeys.SignVerify) {
navigateToSignVerify();
} else if (id === actionKeys.ExportPrivateKey) {
if (await confirm(loc.addresses.sensitive_private_key)) {
if (await isBiometricUseCapableAndEnabled()) {
if (!(await unlockWithBiometrics())) {
return;
const onToolTipPress = useCallback(
async (id: string) => {
if (id === CommonToolTipActions.CopyTXID.id) {
handleCopyPress();
} else if (id === CommonToolTipActions.Share.id) {
handleSharePress();
} else if (id === CommonToolTipActions.SignVerify.id) {
navigateToSignVerify();
} else if (id === CommonToolTipActions.ExportPrivateKey.id) {
if (await confirm(loc.addresses.sensitive_private_key)) {
if (await isBiometricUseCapableAndEnabled()) {
if (!(await unlockWithBiometrics())) {
return;
}
}
handleCopyPrivkeyPress();
}
handleCopyPrivkeyPress();
}
}
};
},
[handleCopyPress, handleSharePress, navigateToSignVerify, handleCopyPrivkeyPress, isBiometricUseCapableAndEnabled],
);
const renderPreview = () => {
return <QRCodeComponent value={item.address} isMenuAvailable={false} />;
};
const renderPreview = useCallback(() => <QRCodeComponent value={item.address} isMenuAvailable={false} />, [item.address]);
const render = () => {
return (
<ToolTipMenu
title={item.address}
actions={menuActions}
onPressMenuItem={onToolTipPress}
renderPreview={renderPreview}
onPress={navigateToReceive}
isButton
>
<ListItem key={item.key} containerStyle={stylesHook.container}>
<ListItem.Content style={stylesHook.list}>
<ListItem.Title style={stylesHook.list} numberOfLines={1} ellipsizeMode="middle">
<Text style={[styles.index, stylesHook.index]}>{item.index + 1}</Text>{' '}
<Text style={[stylesHook.address, styles.address]}>{item.address}</Text>
</ListItem.Title>
<View style={styles.subtitle}>
<Text style={[stylesHook.list, styles.balance, stylesHook.balance]}>{balance}</Text>
</View>
</ListItem.Content>
<View>
<AddressTypeBadge isInternal={item.isInternal} hasTransactions={hasTransactions} />
<Text style={[stylesHook.list, styles.balance, stylesHook.balance]}>
{loc.addresses.transactions}: {item.transactions}
</Text>
return (
<ToolTipMenu
title={item.address}
actions={menuActions}
onPressMenuItem={onToolTipPress}
renderPreview={renderPreview}
onPress={navigateToReceive}
isButton
>
<ListItem key={item.key} containerStyle={stylesHook.container}>
<ListItem.Content style={stylesHook.list}>
<ListItem.Title style={stylesHook.list} numberOfLines={1} ellipsizeMode="middle">
<Text style={[styles.index, stylesHook.index]}>{item.index + 1}</Text>{' '}
<Text style={[stylesHook.address, styles.address]}>{item.address}</Text>
</ListItem.Title>
<View style={styles.subtitle}>
<Text style={[stylesHook.list, styles.balance, stylesHook.balance]}>{balance}</Text>
</View>
</ListItem>
</ToolTipMenu>
);
};
return render();
};
const actionKeys = {
Share: 'share',
CopyToClipboard: 'copyToClipboard',
SignVerify: 'signVerify',
ExportPrivateKey: 'exportPrivateKey',
};
const actionIcons = {
Signature: {
iconValue: 'signature',
},
Share: {
iconValue: 'square.and.arrow.up',
},
Clipboard: {
iconValue: 'doc.on.doc',
},
ExportPrivateKey: {
iconValue: 'key',
},
</ListItem.Content>
<View>
<AddressTypeBadge isInternal={item.isInternal} hasTransactions={hasTransactions} />
<Text style={[stylesHook.list, styles.balance, stylesHook.balance]}>
{loc.addresses.transactions}: {item.transactions}
</Text>
</View>
</ListItem>
</ToolTipMenu>
);
};
const styles = StyleSheet.create({
@ -209,37 +197,4 @@ const styles = StyleSheet.create({
},
});
const getAvailableActions = ({ allowSignVerifyMessage }: { allowSignVerifyMessage: boolean }): Action[] => {
const actions = [
{
id: actionKeys.CopyToClipboard,
text: loc.transactions.details_copy,
icon: actionIcons.Clipboard,
},
{
id: actionKeys.Share,
text: loc.receive.details_share,
icon: actionIcons.Share,
},
];
if (allowSignVerifyMessage) {
actions.push({
id: actionKeys.SignVerify,
text: loc.addresses.sign_title,
icon: actionIcons.Signature,
});
}
if (allowSignVerifyMessage) {
actions.push({
id: actionKeys.ExportPrivateKey,
text: loc.addresses.copy_private_key,
icon: actionIcons.ExportPrivateKey,
});
}
return actions;
};
export { AddressItem };

View File

@ -19,7 +19,7 @@ export interface Action {
}
export interface ToolTipMenuProps {
actions: Action[];
actions: Action[] | Action[][];
children: React.ReactNode;
enableAndroidRipple?: boolean;
dismissMenu?: () => void;

View File

@ -290,7 +290,7 @@
"details_outputs": "المخرجات",
"date": "التاريخ",
"details_received": "التاريخ",
"details_show_in_block_explorer": "العرض في مستكشف الكتل",
"details_view_in_browser": "العرض في مستكشف الكتل",
"details_title": "العملية",
"details_to": "إلى",
"enable_offline_signing": "هذه المحفظة لا يتم استعمالها مع التوقيع دون اتصال. هل ترغب في تمكينه الآن؟",

View File

@ -213,7 +213,7 @@
"details_outputs": "Sortides",
"date": "Data",
"details_received": "Rebut",
"details_show_in_block_explorer": "Mostrar en l'explorador de blocs",
"details_view_in_browser": "Mostrar en l'explorador de blocs",
"details_title": "Transacció",
"details_to": "A",
"list_conf": "Conf: {number}",

View File

@ -344,7 +344,7 @@
"details_outputs": "Výstupy",
"date": "Datum",
"details_received": "Přijato",
"details_show_in_block_explorer": "Zobrazit v průzkumníku bloků",
"details_view_in_browser": "Zobrazit v průzkumníku bloků",
"details_title": "Transakce",
"incoming_transaction": "Příchozí transakce",
"outgoing_transaction": "Odchozí transakce",

View File

@ -72,7 +72,7 @@
"cpfp_create": "Opret",
"details_copy": "Kopier",
"details_from": "Fra",
"details_show_in_block_explorer": "Vis i block-explorer",
"details_view_in_browser": "Vis i block-explorer",
"details_title": "Transaktion",
"details_to": "Til",
"list_title": "transaktioner",

View File

@ -339,7 +339,7 @@
"details_outputs": "Ausgänge",
"date": "Datum",
"details_received": "Empfangen",
"details_show_in_block_explorer": "Im Block-Explorer zeigen",
"details_view_in_browser": "Im Block-Explorer zeigen",
"details_title": "Transaktion",
"incoming_transaction": "Eingehende Transaktion",
"outgoing_transaction": "Ausgehende Transaktion",

View File

@ -223,7 +223,7 @@
"details_from": "Εισερχόμενες διευθύνσεις",
"date": "Ημερομηνία",
"details_received": "Ελήφθη",
"details_show_in_block_explorer": "Προβολή στον block explorer",
"details_view_in_browser": "Προβολή στον block explorer",
"details_title": "Συναλλαγή",
"details_to": "Εξερχόμενες διευθύνσεις",
"pending": "Σε επεξεργασία",

View File

@ -344,7 +344,7 @@
"details_outputs": "Outputs",
"date": "Date",
"details_received": "Received",
"details_show_in_block_explorer": "View in Block Explorer",
"details_view_in_browser": "View in Browser",
"details_title": "Transaction",
"incoming_transaction": "Incoming Transaction",
"outgoing_transaction": "Outgoing Transaction",

View File

@ -280,7 +280,7 @@
"details_outputs": "Outputs",
"date": "Fecha",
"details_received": "Recibido",
"details_show_in_block_explorer": "Mostrar en explorador de bloques",
"details_view_in_browser": "Mostrar en explorador de bloques",
"details_title": "Transaccion",
"details_to": "Destino",
"enable_offline_signing": "Esta billetera no se está usando en conjunción con una firma offline. ¿Quieres activarlo ahora? ",

View File

@ -344,7 +344,7 @@
"details_outputs": "Salidas",
"date": "Fecha",
"details_received": "Recibido",
"details_show_in_block_explorer": "Ver en el Explorador de Bloques",
"details_view_in_browser": "Ver en el Explorador de Bloques",
"details_title": "Transacción",
"incoming_transaction": "Transacción entrante",
"outgoing_transaction": "Transacción saliente",

View File

@ -293,7 +293,7 @@
"details_outputs": "خروجی‌ها",
"date": "تاریخ",
"details_received": "دریافت‌شده",
"details_show_in_block_explorer": "مشاهده در مرورگر بلاک",
"details_view_in_browser": "مشاهده در مرورگر بلاک",
"details_title": "تراکنش",
"details_to": "خروجی",
"enable_offline_signing": "این کیف پول در کنار امضای آفلاین استفاده نمی‌شود. آیا مایل به فعال‌کردن این امکان هستید؟",

View File

@ -309,7 +309,7 @@
"details_outputs": "Ulostulot",
"date": "Päivämäärä",
"details_received": "Vastaanotettu",
"details_show_in_block_explorer": "Näytä lohkoketjuselaimessa",
"details_view_in_browser": "Näytä lohkoketjuselaimessa",
"details_title": "Siirtotapahtuma",
"details_to": "Ulostulo",
"enable_offline_signing": "Tätä lompakkoa ei käytetä offline-allekirjoituksen yhteydessä. Haluatko ottaa sen käyttöön nyt? ",

View File

@ -294,7 +294,7 @@
"details_inputs": "Inputs",
"details_outputs": "Outputs",
"details_received": "Reçu",
"details_show_in_block_explorer": "Afficher dans le \"block explorer\"",
"details_view_in_browser": "Afficher dans le \"block explorer\"",
"details_title": "Transaction",
"details_to": "À",
"enable_offline_signing": "Ce portefeuille n'est pas utilisé en conjonction avec une signature hors ligne. Voulez-vous l'activer maintenant ? ",

View File

@ -323,7 +323,7 @@
"details_outputs": "פלטים",
"date": "תאריך",
"details_received": "התקבל",
"details_show_in_block_explorer": "צפייה בסייר בלוקים",
"details_view_in_browser": "צפייה בסייר בלוקים",
"details_title": "פעולה",
"incoming_transaction": "פעולה נכנסת",
"outgoing_transaction": "פעולה יוצאת",

View File

@ -80,7 +80,7 @@
"cpfp_create": "Stvori",
"details_copy": "Kopiraj",
"details_from": "Od",
"details_show_in_block_explorer": "Prikaži u blok eksploreru",
"details_view_in_browser": "Prikaži u blok eksploreru",
"details_title": "Transakcija",
"details_to": "Za",
"list_title": "transakcije",

View File

@ -288,7 +288,7 @@
"details_inputs": "Bejövő utalások",
"details_outputs": "Kimenő utalások",
"details_received": "Fogadott",
"details_show_in_block_explorer": "Mutasd a block explorerben",
"details_view_in_browser": "Mutasd a block explorerben",
"details_title": "Tranzakció",
"details_to": "Kimenő utalás",
"enable_offline_signing": "Ezt a pénztárcát nem használják offline aláírással. Szeretné most engedélyezni?",

View File

@ -259,7 +259,7 @@
"details_inputs": "Input",
"date": "Tanggal",
"details_received": "Diterima",
"details_show_in_block_explorer": "Tampilkan di block explorer",
"details_view_in_browser": "Tampilkan di block explorer",
"details_title": "Transaksi",
"pending": "tertunda",
"pending_with_amount": "Tertunda {amt1} ({amt2})",

View File

@ -288,7 +288,7 @@
"details_outputs": "Output",
"date": "Data",
"details_received": "Ricevuto",
"details_show_in_block_explorer": "Mostra sul block explorer",
"details_view_in_browser": "Mostra sul block explorer",
"details_title": "Transazione",
"details_to": "A",
"enable_offline_signing": "Questo wallet non sta venendo usato con la firma offline. Desideri attivarla adesso?",

View File

@ -339,7 +339,7 @@
"details_outputs": "アウトプット",
"date": "日付",
"details_received": "受取り済",
"details_show_in_block_explorer": "Block Explorer で表示",
"details_view_in_browser": "Block Explorer で表示",
"details_title": "取引",
"incoming_transaction": "受取りトランザクション",
"outgoing_transaction": "支払いトランザクション",

View File

@ -273,7 +273,7 @@
"details_inputs": "입력",
"details_outputs": "출력",
"details_received": "받기 완료",
"details_show_in_block_explorer": "블록 익스플로러에서 보기",
"details_view_in_browser": "블록 익스플로러에서 보기",
"details_title": "트랜잭션",
"details_to": "출력",
"enable_offline_signing": "이 지갑은 오프라인 서명과 함께 쓸수 없습니다. 지금 가능하도록 할까요?",

View File

@ -255,7 +255,7 @@
"details_inputs": "Masukan",
"details_outputs": "Keluaran",
"details_received": "Diterima",
"details_show_in_block_explorer": "Lihat di Penjelajah Bongkah.",
"details_view_in_browser": "Lihat di Penjelajah Bongkah.",
"details_title": "Urus niaga",
"details_to": "Keluaran",
"enable_offline_signing": "Dompet ini tidak digunakan bersama dengan penandatanganan luar talian. Adakah anda mahu membolehkan ciri ini sekarang?",

View File

@ -275,7 +275,7 @@
"details_inputs": "Inndata",
"details_outputs": "Utdata",
"details_received": "Mottatt",
"details_show_in_block_explorer": "Vis i Block Explorer",
"details_view_in_browser": "Vis i Block Explorer",
"details_title": "Transaksjon",
"details_to": "Utdata",
"enable_offline_signing": "Denne lommeboken brukes ikke i forbindelse med en offline-signering. Vil du aktivere det nå?",

View File

@ -280,7 +280,7 @@
"details_inputs": "Inputs",
"details_outputs": "Outputs",
"details_received": "Ontvangen",
"details_show_in_block_explorer": "Weergeven in block explorer",
"details_view_in_browser": "Weergeven in block explorer",
"details_title": "Transacties",
"details_to": "Uitvoer",
"enable_offline_signing": "Deze wallet wordt niet gebruikt in combinatie met een hardware wallet. Wilt u het gebruik inschakelen?",

View File

@ -333,7 +333,7 @@
"details_outputs": "Wyjścia",
"date": "Data",
"details_received": "Otrzymano",
"details_show_in_block_explorer": "Zobacz w eksploratorze bloków",
"details_view_in_browser": "Zobacz w eksploratorze bloków",
"details_title": "Transakcja",
"incoming_transaction": "Transakcja przychodząca",
"outgoing_transaction": "Transakcja wychodząca",

View File

@ -333,7 +333,7 @@
"details_outputs": "Saídas",
"date": "Data",
"details_received": "Recebido",
"details_show_in_block_explorer": "Ver no Explorador de Blocos",
"details_view_in_browser": "Ver no Explorador de Blocos",
"details_title": "Transação",
"incoming_transaction": "Transação de Entrada",
"outgoing_transaction": "Transação de Saída",

View File

@ -244,7 +244,7 @@
"details_outputs": "Outputs",
"date": "Data",
"details_received": "Recebido",
"details_show_in_block_explorer": "Mostrar no block explorer",
"details_view_in_browser": "Mostrar no block explorer",
"details_title": "detalhes",
"details_to": "Para",
"enable_offline_signing": "Esta carteira não está a ser utilizada em conjunto com uma assinatura offline. Deseja activá-la agora?",

View File

@ -262,7 +262,7 @@
"details_inputs": "Input-uri",
"details_outputs": "Output-uri",
"details_received": "Primit",
"details_show_in_block_explorer": "Afișează în Block Explorer",
"details_view_in_browser": "Afișează în Block Explorer",
"details_title": "Tranzacție",
"details_to": "Output",
"enable_offline_signing": "Acest portofel nu este folosit în legătură cu o semnare offline. Ai vrea să activezi asta acum?",

View File

@ -344,7 +344,7 @@
"details_outputs": "Выходы",
"date": "Дата",
"details_received": "Получена",
"details_show_in_block_explorer": "Показать в блокчейне",
"details_view_in_browser": "Показать в блокчейне",
"details_title": "Детали транзакции",
"incoming_transaction": "Входящая транзакция",
"outgoing_transaction": "Исходящая транзакция",

View File

@ -271,7 +271,7 @@
"details_inputs": "යෙදවුම්",
"details_outputs": "ප්‍රතිදාන",
"details_received": "ලැබුණි",
"details_show_in_block_explorer": "බ්ලොක් එක්ස්ප්ලෝරර් හි බලන්න",
"details_view_in_browser": "බ්ලොක් එක්ස්ප්ලෝරර් හි බලන්න",
"details_title": "ගනුදෙනුව",
"details_to": "ප්‍රතිදානය",
"enable_offline_signing": "මෙම පසුම්බිය නොබැඳි අත්සන් කිරීම සමඟ එක්ව භාවිතා නොකෙරේ. ඔබ දැන් එය සක්‍රීය කිරීමට කැමතිද?",

View File

@ -156,7 +156,7 @@
"details_inputs": "Vstupy",
"details_outputs": "Výstupy",
"details_received": "Prijaté",
"details_show_in_block_explorer": "Ukázať v block exploreri",
"details_view_in_browser": "Ukázať v block exploreri",
"details_title": "Transakcia",
"details_to": "Výstup",
"pending": "Čaká...",

View File

@ -280,7 +280,7 @@
"details_outputs": "Izhodi",
"date": "Datum",
"details_received": "Prejeto",
"details_show_in_block_explorer": "Prikaži v raziskovalcu blokov",
"details_view_in_browser": "Prikaži v raziskovalcu blokov",
"details_title": "Transakcija",
"details_to": "Izhod",
"enable_offline_signing": "Ta denarnica se ne uporablja skupaj s podpisovanjem brez povezave (offline). Ali ga želite omogočiti?",

View File

@ -289,7 +289,7 @@
"details_outputs": "Outputs",
"date": "Datum",
"details_received": "Mottaget",
"details_show_in_block_explorer": "Visa i block explorer",
"details_view_in_browser": "Visa i block explorer",
"details_title": "Transaktion",
"details_to": "Output",
"enable_offline_signing": "Den här plånboken används inte i samband med en offlinesignering. Skulle du vilja aktivera det nu?",

View File

@ -201,7 +201,7 @@
"details_inputs": "อินพุท",
"details_outputs": "เอ้าพุท",
"details_received": "ได้รับแล้ว",
"details_show_in_block_explorer": "แสดงด้วย block explorer",
"details_view_in_browser": "แสดงด้วย block explorer",
"details_title": "ธุรกรรม",
"details_to": "เอ้าพุท",
"pending": "รอดำเนินการ",

View File

@ -159,7 +159,7 @@
"cpfp_create": "Oluştur",
"details_copy": "Kopya",
"details_from": "Girdi",
"details_show_in_block_explorer": "Blok gezgininde göster",
"details_view_in_browser": "Blok gezgininde göster",
"details_title": "İşlem",
"details_to": ıktı",
"pending": "Beklemede",

View File

@ -210,7 +210,7 @@
"details_copy_amount": "Копіювати Суму",
"details_copy_note": "Копіювати Нотатку",
"details_from": "Від",
"details_show_in_block_explorer": "Show in block explorer",
"details_view_in_browser": "Show in block explorer",
"details_title": "Деталі транзакції",
"details_to": "Кому",
"pending": "Очікування",

View File

@ -283,7 +283,7 @@
"details_outputs": "Các đầu ra",
"date": "Ngày",
"details_received": "Đã nhận",
"details_show_in_block_explorer": "Xem trong Block Explorer",
"details_view_in_browser": "Xem trong Block Explorer",
"details_title": "Giao dịch",
"details_to": "Đầu ra",
"enable_offline_signing": "Ví này không được sử dụng cùng với một bản ký ngoại tuyến. Bạn có muốn kích hoạt nó ngay bây giờ không?",

View File

@ -154,7 +154,7 @@
"cpfp_create": "Skep",
"details_copy": "Kopieer",
"details_from": "Inset",
"details_show_in_block_explorer": "Wys in blok verkenner",
"details_view_in_browser": "Wys in blok verkenner",
"details_title": "Transaksie",
"details_to": "Resultaat",
"list_title": "transaksies",

View File

@ -93,7 +93,7 @@
"cpfp_create": "Yakha",
"details_copy": "Ikopi",
"details_from": "Negalelo",
"details_show_in_block_explorer": "Bonisa ibhloko umhloi",
"details_view_in_browser": "Bonisa ibhloko umhloi",
"details_title": "Ngeniswa",
"details_to": "Mveliso",
"list_title": "ngeniswa",

View File

@ -241,7 +241,7 @@
"details_inputs": "输入",
"details_outputs": "输出",
"details_received": "已收到",
"details_show_in_block_explorer": "在区块浏览器查看",
"details_view_in_browser": "在区块浏览器查看",
"details_title": "转账",
"details_to": "输出",
"enable_offline_signing": "此钱包未与线下签名结合使用。您想立即启用它吗?",

View File

@ -237,7 +237,7 @@
"details_inputs": "輸入",
"details_outputs": "輸出",
"details_received": "已收到",
"details_show_in_block_explorer": "區塊瀏覽器展示",
"details_view_in_browser": "區塊瀏覽器展示",
"details_title": "轉賬",
"details_to": "輸出",
"enable_offline_signing": "此錢包未與線下簽名結合使用。您想立即啟用它嗎?",

View File

@ -165,7 +165,7 @@ const ReceiveDetails = () => {
}, [showConfirmedBalance]);
const toolTipActions = useMemo(() => {
const action = CommonToolTipActions.PaymentCode;
const action = CommonToolTipActions.PaymentsCode;
action.menuState = wallet?.isBIP47Enabled();
return [action];
}, [wallet]);

View File

@ -160,7 +160,7 @@ const Broadcast: React.FC = () => {
<BlueSpacing20 />
</BlueCard>
)}
{BROADCAST_RESULT.success === broadcastResult && tx && <SuccessScreen tx={tx} url={`${selectedBlockExplorer}/tx/${tx}`} />}
{BROADCAST_RESULT.success === broadcastResult && tx && <SuccessScreen tx={tx} url={`${selectedBlockExplorer.url}/tx/${tx}`} />}
</View>
</SafeArea>
);

View File

@ -51,13 +51,13 @@ import { SendDetailsStackParamList } from '../../navigation/SendDetailsStackPara
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { ContactList } from '../../class/contact-list';
import { useStorage } from '../../hooks/context/useStorage';
import { Action } from '../../components/types';
import SelectFeeModal from '../../components/SelectFeeModal';
import { useKeyboard } from '../../hooks/useKeyboard';
import { DismissKeyboardInputAccessory, DismissKeyboardInputAccessoryViewID } from '../../components/DismissKeyboardInputAccessory';
import ActionSheet from '../ActionSheet';
import HeaderMenuButton from '../../components/HeaderMenuButton';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
import { Action } from '../../components/types';
interface IPaymentDestinations {
address: string; // btc address or payment code
@ -942,23 +942,23 @@ const SendDetails = () => {
handleAddRecipient();
} else if (id === CommonToolTipActions.RemoveRecipient.id) {
handleRemoveRecipient();
} else if (id === SendDetails.actionKeys.SignPSBT) {
} else if (id === CommonToolTipActions.SignPSBT.id) {
handlePsbtSign();
} else if (id === SendDetails.actionKeys.SendMax) {
} else if (id === CommonToolTipActions.SendMax.id) {
onUseAllPressed();
} else if (id === SendDetails.actionKeys.AllowRBF) {
} else if (id === CommonToolTipActions.AllowRBF.id) {
onReplaceableFeeSwitchValueChanged(!isTransactionReplaceable);
} else if (id === SendDetails.actionKeys.ImportTransaction) {
} else if (id === CommonToolTipActions.ImportTransaction.id) {
importTransaction();
} else if (id === SendDetails.actionKeys.ImportTransactionQR) {
} else if (id === CommonToolTipActions.ImportTransactionQR.id) {
importQrTransaction();
} else if (id === SendDetails.actionKeys.ImportTransactionMultsig) {
} else if (id === CommonToolTipActions.ImportTransactionMultsig.id) {
importTransactionMultisig();
} else if (id === SendDetails.actionKeys.CoSignTransaction) {
} else if (id === CommonToolTipActions.CoSignTransaction.id) {
importTransactionMultisigScanQr();
} else if (id === SendDetails.actionKeys.CoinControl) {
} else if (id === CommonToolTipActions.CoinControl.id) {
handleCoinControl();
} else if (id === SendDetails.actionKeys.InsertContact) {
} else if (id === CommonToolTipActions.InsertContact.id) {
handleInsertContact();
} else if (id === CommonToolTipActions.RemoveAllRecipients.id) {
handleRemoveAllRecipients();
@ -966,66 +966,73 @@ const SendDetails = () => {
};
const headerRightActions = () => {
const actions: Action[] & Action[][] = [];
if (isEditable) {
if (wallet?.allowBIP47() && wallet?.isBIP47Enabled()) {
actions.push([
{ id: SendDetails.actionKeys.InsertContact, text: loc.send.details_insert_contact, icon: SendDetails.actionIcons.InsertContact },
]);
}
if (!wallet) return [];
if (Number(wallet?.getBalance()) > 0) {
const isSendMaxUsed = addresses.some(element => element.amount === BitcoinUnit.MAX);
const walletActions: Action[][] = [];
actions.push([{ id: SendDetails.actionKeys.SendMax, text: loc.send.details_adv_full, disabled: balance === 0 || isSendMaxUsed }]);
}
if (wallet?.type === HDSegwitBech32Wallet.type && isTransactionReplaceable !== undefined) {
actions.push([{ id: SendDetails.actionKeys.AllowRBF, text: loc.send.details_adv_fee_bump, menuState: !!isTransactionReplaceable }]);
}
const transactionActions = [];
if (wallet?.type === WatchOnlyWallet.type && wallet.isHd()) {
transactionActions.push(
{
id: SendDetails.actionKeys.ImportTransaction,
text: loc.send.details_adv_import,
icon: SendDetails.actionIcons.ImportTransaction,
},
{
id: SendDetails.actionKeys.ImportTransactionQR,
text: loc.send.details_adv_import_qr,
icon: SendDetails.actionIcons.ImportTransactionQR,
},
);
}
if (wallet?.type === MultisigHDWallet.type) {
transactionActions.push({
id: SendDetails.actionKeys.ImportTransactionMultsig,
text: loc.send.details_adv_import,
icon: SendDetails.actionIcons.ImportTransactionMultsig,
});
}
if (wallet?.type === MultisigHDWallet.type && wallet.howManySignaturesCanWeMake() > 0) {
transactionActions.push({
id: SendDetails.actionKeys.CoSignTransaction,
text: loc.multisig.co_sign_transaction,
icon: SendDetails.actionIcons.SignPSBT,
});
}
if ((wallet as MultisigHDWallet)?.allowCosignPsbt()) {
transactionActions.push({ id: SendDetails.actionKeys.SignPSBT, text: loc.send.psbt_sign, icon: SendDetails.actionIcons.SignPSBT });
}
actions.push(transactionActions);
const recipientActions: Action[] = [
CommonToolTipActions.AddRecipient,
CommonToolTipActions.RemoveRecipient,
{
...CommonToolTipActions.RemoveAllRecipients,
hidden: !(addresses.length > 1),
},
];
walletActions.push(recipientActions);
const recipientActions: Action[] = [CommonToolTipActions.AddRecipient, CommonToolTipActions.RemoveRecipient];
if (addresses.length > 1) {
recipientActions.push(CommonToolTipActions.RemoveAllRecipients);
}
actions.push(recipientActions);
}
const isSendMaxUsed = addresses.some(element => element.amount === BitcoinUnit.MAX);
const sendMaxAction: Action[] = [
{
...CommonToolTipActions.SendMax,
disabled: wallet.getBalance() === 0 || isSendMaxUsed,
hidden: !isEditable || !(Number(wallet.getBalance()) > 0),
},
];
walletActions.push(sendMaxAction);
actions.push({ id: SendDetails.actionKeys.CoinControl, text: loc.cc.header, icon: SendDetails.actionIcons.CoinControl });
const rbfAction: Action[] = [
{
...CommonToolTipActions.AllowRBF,
menuState: isTransactionReplaceable,
hidden: !(wallet.type === HDSegwitBech32Wallet.type && isTransactionReplaceable !== undefined),
},
];
walletActions.push(rbfAction);
return actions;
const transactionActions: Action[] = [
{
...CommonToolTipActions.ImportTransaction,
hidden: !(wallet.type === WatchOnlyWallet.type && wallet.isHd()),
},
{
...CommonToolTipActions.ImportTransactionQR,
hidden: !(wallet.type === WatchOnlyWallet.type && wallet.isHd()),
},
{
...CommonToolTipActions.ImportTransactionMultsig,
hidden: !(wallet.type === MultisigHDWallet.type),
},
{
...CommonToolTipActions.CoSignTransaction,
hidden: !(wallet.type === MultisigHDWallet.type && wallet.howManySignaturesCanWeMake() > 0),
},
{
...CommonToolTipActions.SignPSBT,
hidden: !(wallet as MultisigHDWallet)?.allowCosignPsbt(),
},
];
walletActions.push(transactionActions);
const specificWalletActions: Action[] = [
{
...CommonToolTipActions.InsertContact,
hidden: !(isEditable && wallet.allowBIP47() && wallet.isBIP47Enabled()),
},
CommonToolTipActions.CoinControl,
];
walletActions.push(specificWalletActions);
return walletActions;
};
const setHeaderRightOptions = () => {
@ -1354,29 +1361,6 @@ const SendDetails = () => {
export default SendDetails;
SendDetails.actionKeys = {
InsertContact: 'InsertContact',
SignPSBT: 'SignPSBT',
SendMax: 'SendMax',
AllowRBF: 'AllowRBF',
ImportTransaction: 'ImportTransaction',
ImportTransactionMultsig: 'ImportTransactionMultisig',
ImportTransactionQR: 'ImportTransactionQR',
CoinControl: 'CoinControl',
CoSignTransaction: 'CoSignTransaction',
};
SendDetails.actionIcons = {
InsertContact: { iconValue: 'at.badge.plus' },
SignPSBT: { iconValue: 'signature' },
SendMax: 'SendMax',
AllowRBF: 'AllowRBF',
ImportTransaction: { iconValue: 'square.and.arrow.down' },
ImportTransactionMultsig: { iconValue: 'square.and.arrow.down.on.square' },
ImportTransactionQR: { iconValue: 'qrcode.viewfinder' },
CoinControl: { iconValue: 'switch.2' },
};
const styles = StyleSheet.create({
root: {
flex: 1,

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { Platform, Pressable, ScrollView, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
import { Platform, ScrollView, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
import { openSettings } from 'react-native-permissions';
import A from '../../blue_modules/analytics';
import { Header } from '../../components/Header';
@ -127,11 +127,7 @@ const SettingsPrivacy: React.FC = () => {
disabled: isLoading === SettingsPrivacySection.All,
testID: 'ClipboardSwitch',
}}
subtitle={
<Pressable accessibilityRole="button">
<Text style={styles.subtitleText}>{loc.settings.privacy_clipboard_explanation}</Text>
</Pressable>
}
subtitle={loc.settings.privacy_clipboard_explanation}
/>
<ListItem

View File

@ -347,7 +347,7 @@ const TransactionDetails = () => {
onPress={handleOnOpenTransactionOnBlockExplorerTapped}
buttonStyle={StyleSheet.flatten([styles.greyButton, stylesHooks.greyButton])}
>
<Text style={[styles.Link, stylesHooks.Link]}>{loc.transactions.details_show_in_block_explorer}</Text>
<Text style={[styles.Link, stylesHooks.Link]}>{loc.transactions.details_view_in_browser}</Text>
</ToolTipMenu>
</BlueCard>
</ScrollView>

View File

@ -1,4 +1,6 @@
import { Platform } from 'react-native';
import loc from '../loc';
import { Action } from '../components/types';
const keys = {
CopyTXID: 'copyTX_ID',
@ -25,70 +27,65 @@ const keys = {
RemoveAllRecipients: 'RemoveAllRecipients',
AddRecipient: 'AddRecipient',
RemoveRecipient: 'RemoveRecipient',
ChoosePhoto: 'choose_photo',
ImportFile: 'import_file',
InsertContact: 'insert_contact',
SignPSBT: 'sign_psbt',
SendMax: 'send_max',
AllowRBF: 'allow_rbf',
ImportTransaction: 'import_transaction',
ImportTransactionMultsig: 'import_transaction_multisig',
ImportTransactionQR: 'import_transaction_qr',
CoinControl: 'coin_control',
CoSignTransaction: 'co_sign_transaction',
CopyToClipboard: 'copyToClipboard',
Share: 'share',
SignVerify: 'signVerify',
ExportPrivateKey: 'exportPrivateKey',
PasteFromClipboard: 'pasteFromClipboard',
ChoosePhoto: 'choosePhoto',
ImportFile: 'importFile',
};
const icons = {
Eye: {
iconValue: 'eye',
},
EyeSlash: {
iconValue: 'eye.slash',
},
Clipboard: {
iconValue: 'doc.on.doc',
},
Link: {
iconValue: 'link',
},
Note: {
iconValue: 'note.text',
},
ManageWallets: {
iconValue: 'slider.horizontal.3',
},
ImportWallet: {
iconValue: 'square.and.arrow.down.on.square',
},
ViewInBitcoin: {
iconValue: 'bitcoinsign.circle',
},
ViewInFiat: {
iconValue: 'coloncurrencysign.circle',
},
Entropy: {
iconValue: 'dice',
},
SearchAccount: {
iconValue: 'magnifyingglass',
},
Passphrase: {
iconValue: 'rectangle.and.pencil.and.ellipsis',
},
MoreInfo: {
iconValue: 'info.circle',
},
SaveChanges: {
iconValue: 'checkmark',
},
PaymentsCode: {
iconValue: 'qrcode',
},
const icons: { [key: string]: { iconValue: string } } = {
Eye: { iconValue: 'eye' },
EyeSlash: { iconValue: 'eye.slash' },
Link: { iconValue: 'link' },
Note: { iconValue: 'note.text' },
ManageWallets: { iconValue: 'slider.horizontal.3' },
ImportWallet: { iconValue: 'square.and.arrow.down.on.square' },
ViewInBitcoin: { iconValue: 'bitcoinsign.circle' },
ViewInFiat: { iconValue: 'coloncurrencysign.circle' },
Entropy: { iconValue: 'dice' },
SearchAccount: { iconValue: 'magnifyingglass' },
Passphrase: { iconValue: 'rectangle.and.pencil.and.ellipsis' },
MoreInfo: { iconValue: 'info.circle' },
SaveChanges: { iconValue: 'checkmark' },
InsertContact: { iconValue: 'at.badge.plus' },
SignPSBT: { iconValue: 'signature' },
SendMax: { iconValue: 'dial.high' },
AllowRBF: { iconValue: 'arrowshape.up.circle' },
ImportTransaction: { iconValue: 'square.and.arrow.down' },
ImportTransactionMultsig: { iconValue: 'square.and.arrow.down.on.square' },
ImportTransactionQR: { iconValue: 'qrcode.viewfinder' },
CoinControl: { iconValue: 'switch.2' },
CoSignTransaction: { iconValue: 'signature' },
PaymentsCode: { iconValue: 'qrcode.viewfinder' },
ClearHistory: {
iconValue: 'trash',
},
RemoveAllRecipients: { iconValue: 'person.2.slash' },
AddRecipient: { iconValue: 'person.badge.plus' },
RemoveRecipient: { iconValue: 'person.badge.minus' },
ScanQR: { iconValue: Platform.OS === 'ios' ? 'qrcode.viewfinder' : 'ic_menu_camera' },
ChoosePhoto: { iconValue: Platform.OS === 'ios' ? 'photo.on.rectangle' : 'ic_menu_gallery' },
Clipboard: { iconValue: Platform.OS === 'ios' ? 'document.on.clipboard' : 'ic_menu_file' },
ExportPrivateKey: { iconValue: 'key' },
Share: { iconValue: 'square.and.arrow.up' },
Signature: { iconValue: 'signature' },
PasteFromClipboard: { iconValue: 'document.on.clipboard' },
ScanQR: { iconValue: 'qrcode.viewfinder' },
ChoosePhoto: { iconValue: 'photo.on.rectangle' },
ImportFile: { iconValue: 'doc.badge.plus' },
ImportFile: { iconValue: 'document.viewfinder' },
};
export const CommonToolTipActions = {
export const CommonToolTipActions: { [key: string]: Action } = {
CopyTXID: {
id: keys.CopyTXID,
text: loc.transactions.details_copy_txid,
@ -101,7 +98,7 @@ export const CommonToolTipActions = {
},
OpenInBlockExplorer: {
id: keys.OpenInBlockExplorer,
text: loc.transactions.details_show_in_block_explorer,
text: loc.transactions.details_view_in_browser,
icon: icons.Link,
},
ExpandNote: {
@ -195,12 +192,102 @@ export const CommonToolTipActions = {
text: loc._.save,
icon: icons.SaveChanges,
},
PaymentCode: {
PaymentsCode: {
id: keys.PaymentsCode,
text: loc.bip47.purpose,
icon: icons.PaymentsCode,
menuState: false,
},
ScanQR: {
id: keys.ScanQR,
text: loc.wallets.list_long_scan,
icon: icons.ScanQR,
},
ChoosePhoto: {
id: keys.ChoosePhoto,
text: loc.wallets.list_long_choose,
icon: icons.ChoosePhoto,
},
ImportFile: {
id: keys.ImportFile,
text: loc.wallets.import_file,
icon: icons.ImportFile,
},
InsertContact: {
id: keys.InsertContact,
text: loc.send.details_insert_contact,
icon: icons.InsertContact,
hidden: true,
},
SignPSBT: {
id: keys.SignPSBT,
text: loc.send.psbt_sign,
icon: icons.SignPSBT,
hidden: true,
},
SendMax: {
id: keys.SendMax,
text: loc.send.details_adv_full,
icon: icons.SendMax,
hidden: true,
},
AllowRBF: {
id: keys.AllowRBF,
text: loc.send.details_adv_fee_bump,
icon: icons.AllowRBF,
hidden: true,
menuState: false,
},
ImportTransaction: {
id: keys.ImportTransaction,
text: loc.send.details_adv_import,
icon: icons.ImportTransaction,
hidden: true,
},
ImportTransactionQR: {
id: keys.ImportTransactionQR,
text: loc.send.details_adv_import_qr,
icon: icons.ImportTransactionQR,
hidden: true,
},
ImportTransactionMultsig: {
id: keys.ImportTransactionMultsig,
text: loc.send.details_adv_import,
icon: icons.ImportTransactionMultsig,
hidden: true,
},
CoSignTransaction: {
id: keys.CoSignTransaction,
text: loc.multisig.co_sign_transaction,
icon: icons.CoSignTransaction,
hidden: true,
},
CoinControl: {
id: keys.CoinControl,
text: loc.cc.header,
icon: icons.CoinControl,
hidden: false,
},
CopyToClipboard: {
id: keys.CopyToClipboard,
text: loc.transactions.details_copy,
icon: icons.Clipboard,
},
Share: {
id: keys.Share,
text: loc.receive.details_share,
icon: icons.Share,
},
SignVerify: {
id: keys.SignVerify,
text: loc.addresses.sign_title,
icon: icons.Signature,
},
ExportPrivateKey: {
id: keys.ExportPrivateKey,
text: loc.addresses.copy_private_key,
icon: icons.ExportPrivateKey,
},
ResetToDefault: {
id: keys.ResetToDefault,
text: loc.settings.electrum_reset,
@ -212,22 +299,7 @@ export const CommonToolTipActions = {
},
PasteFromClipboard: {
id: keys.PasteFromClipboard,
text: loc.transactions.details_copy_amount,
text: loc.wallets.paste_from_clipboard,
icon: icons.PasteFromClipboard,
},
ScanQR: {
id: keys.ScanQR,
text: loc.send.details_scan,
icon: icons.ScanQR,
},
ChoosePhoto: {
id: keys.ChoosePhoto,
text: loc._.pick_image,
icon: icons.ChoosePhoto,
},
ImportFile: {
id: keys.ImportFile,
text: loc.wallets.import_file,
icon: icons.ImportFile,
},
};