Skip to content

Commit

Permalink
Merge pull request #242 from rastajpa/send-to-options
Browse files Browse the repository at this point in the history
[RN-496 & RN-510] Select Inputs & Multiple Recipients
  • Loading branch information
JohnathanWhite authored Jul 19, 2022
2 parents 9796cf2 + d0c8647 commit b370bb4
Show file tree
Hide file tree
Showing 19 changed files with 1,641 additions and 55 deletions.
23 changes: 20 additions & 3 deletions locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,12 @@
"Password removed": "Password removed",
"Your encryption password has been removed. This key is now decrypted.": "Your encryption password has been removed. This key is now decrypted.",
"To disable encryption for your wallet, please enter your encryption password below.": "To disable encryption for your wallet, please enter your encryption password below.",
"Generating Address": "Generating Address",
"Enter address or select wallet": "Enter address or select wallet",
"Recipients": "Recipients",
"Recipient": "Recipient",
"To get started, you’ll need to enter a valid address or select an existing contact or wallet.": "To get started, you’ll need to enter a valid address or select an existing contact or wallet.",
"Search contact": "Search contact",
"Select Wallet Type": "Select Wallet Type",
"Basic wallet": "Basic wallet",
"Add coins like Bitcoin and Dogecoin, and also tokens like USDC and PAX": "Add coins like Bitcoin and Dogecoin, and also tokens like USDC and PAX",
Expand Down Expand Up @@ -922,6 +928,12 @@
"Payment Request": "Payment Request",
"Share this QR code to receive in your wallet .": "Share this QR code to receive {{amountUnitStr}} in your wallet {{walletName}}.",
"Receive ": "Receive ",
"Select Inputs": "Select Inputs",
"Specify Amount": "Specify Amount",
"Total Selected Inputs": "Total Selected Inputs",
"The sum of the selected amounts must be at least:": "The sum of the selected amounts must be at least: {{specifiedAmount}} {{currencyAbbreviation}}",
"Wallet Inputs": "Wallet Inputs",
"No available inputs.": "No available inputs.",
"Confirm ": "Confirm {{title}}",
"Enable Replace-By-Fee": "Enable Replace-By-Fee",
"Edit gas limit": "Edit gas limit",
Expand All @@ -947,9 +959,13 @@
"Please enter a valid verification code.": "Please enter a valid verification code.",
" ( of total amount)": "{{fiatAmount}} ({{percentageOfTotalAmount}} of total amount)",
"Sending from": "Sending from",
"Select Inputs for this Transaction": "Select Inputs for this Transaction",
"Choose which inputs you'd like to use to send crypto.": "Choose which inputs you'd like to use to send crypto.",
"Transfer to Multiple Recipients": "Transfer to Multiple Recipients",
"Send crypto to multiple contacts or addresses.": "Send crypto to multiple contacts or addresses.",
"Multiple Recipients": "Multiple Recipients",
"Send To": "Send To",
"Fetching payment options...": "Fetching payment options...",
"Generating Address": "Generating Address",
"Search contact or enter address": "Search contact or enter address",
"Paste from clipboard": "Paste from clipboard",
"Could not get fee levels": "Could not get fee levels",
Expand All @@ -961,6 +977,7 @@
"Fee should be higher than ": "Fee should be higher than ",
"Fee Should be lesser than ": "Fee Should be lesser than ",
"Apply": "Apply",
"Addresses": "Addresses",
"Test Only - No Value": "Test Only - No Value",
"Interaction with contract": "Interaction with contract",
"Error encountered during contract execution ()": "Error encountered during contract execution ({{error}})",
Expand Down Expand Up @@ -1000,13 +1017,11 @@
"The recovery phrase you provided was incorrect.": "The recovery phrase you provided was incorrect.",
"TRY AGAIN": "TRY AGAIN",
"Tap each word in the correct order.": "Tap each word in the correct order.",
"Addresses": "Addresses",
"Could not update wallet": "Could not update wallet",
"Each wallet (except for ETH/ERC20) can generate billions of addresses from your 12-word recovery phrase. A new address is automatically generated and shown each time you receive a payment.": "Each wallet (except for ETH/ERC20) can generate billions of addresses from your 12-word recovery phrase. A new address is automatically generated and shown each time you receive a payment.",
"It's a good idea to avoid reusing addresses - this both protects your privacy and keeps your bitcoins secure against hypothetical attacks by quantum computers.": "It's a good idea to avoid reusing addresses - this both protects your privacy and keeps your bitcoins secure against hypothetical attacks by quantum computers.",
"Scan Addresses for Funds": "Scan Addresses for Funds",
"View all addresses": "View all addresses",
"Wallet Inputs": "Wallet Inputs",
"Total wallet inputs": "Total wallet inputs",
"Low amount inputs": "Low amount inputs",
"Approximate Bitcoin network fee to transfer wallet's balance (with normal priority)": "Approximate Bitcoin network fee to transfer wallet's balance (with normal priority)",
Expand Down Expand Up @@ -1078,6 +1093,8 @@
"Verification Required": "Verification Required",
"To complete this payment please verify your account.": "To complete this payment please verify your account.",
"Verify": "Verify",
"Connect Your BitPay ID": "Connect Your BitPay ID",
"To complete this payment, please login with your BitPay ID.": "To complete this payment, please login with your BitPay ID.",
"Session request failed or rejected. Please try again by refreshing the QR code.": "Session request failed or rejected. Please try again by refreshing the QR code.",
"20 Wallet limit from the same coin and network has been reached.": "20 Wallet limit from the same coin and network has been reached.",
"High": "High",
Expand Down
19 changes: 16 additions & 3 deletions locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,10 @@
"Password removed": "Contraseña eliminada",
"Your encryption password has been removed. This key is now decrypted.": "Su contraseña de cifrado ha sido eliminada. Esta clave ahora está descifrada.",
"To disable encryption for your wallet, please enter your encryption password below.": "Para desactivar el cifrado de su billetera, por favor introduzca su contraseña de cifrado a continuación.",
"Generating Address": "Generando dirección",
"To get started, you’ll need to enter a valid address or select an existing contact or wallet.": "Para comenzar, deberá ingresar una dirección válida o seleccionar un contacto o billetera existente.",
"Enter address or select wallet": "Ingrese una dirección o seleccione una billetera",
"Search contact": "Buscar contacto",
"Select Wallet Type": "Seleccionar tipo de billetera",
"Basic wallet": "Billetera básica",
"Add coins like Bitcoin and Dogecoin, and also tokens like USDC and PAX": "Agrega monedas como Bitcoin y Dogecoin, y también tokens como USDC y PAX",
Expand Down Expand Up @@ -914,6 +918,13 @@
"Payment Request": "Solicitud de pago",
"Share this QR code to receive in your wallet .": "Comparte este código QR para recibir {{amountUnitStr}} en su billetera {{walletName}}.",
"Receive ": "Recibir ",
"Select Inputs": "Seleccionar inputs",
"Recipient": "Destinatario",
"Specify Amount": "Especificar Monto",
"Total Selected Inputs": "Total de inputs seleccionados",
"The sum of the selected amounts must be at least:": "La suma de los inputs seleccionados debe ser como mínimo: {{specifiedAmount}} {{currencyAbbreviation}}",
"Wallet Inputs": "Inputs de la billetera",
"No available inputs.": "No hay inputs disponibles.",
"Confirm ": "Confirmar {{title}}",
"Enable Replace-By-Fee": "Habilitar Replace-By-Fee",
"Edit gas limit": "Modificar límite de gas",
Expand All @@ -939,9 +950,10 @@
"Please enter a valid verification code.": "Por favor, introduzca un código de verificación válido.",
" ( of total amount)": "{{fiatAmount}} ({{percentageOfTotalAmount}} del monto total)",
"Sending from": "Enviando desde",
"Select Inputs for this Transaction": "Seleccionar inputs para esta transacción",
"Choose which inputs you'd like to use to send crypto.": "Elija qué inputs le gustaría usar para enviar criptomonedas.",
"Send To": "Enviar a",
"Fetching payment options...": "Obteniendo opciones de pago...",
"Generating Address": "Generando dirección",
"Search contact or enter address": "Buscar contacto o ingresar dirección",
"Paste from clipboard": "Pegar desde el portapapeles",
"Could not get fee levels": "No se pudo obtener los niveles de comisión",
Expand All @@ -953,6 +965,7 @@
"Fee should be higher than ": "La comisión debe ser mayor que ",
"Fee Should be lesser than ": "La comisión debe ser menor que ",
"Apply": "Aplicar",
"Addresses": "Direcciones",
"Test Only - No Value": "Solo prueba - Sin valor",
"Interaction with contract": "Interacción con contrato",
"Error encountered during contract execution ()": "Error encontrado durante la ejecución del contrato ({{error}})",
Expand Down Expand Up @@ -992,13 +1005,11 @@
"The recovery phrase you provided was incorrect.": "La frase de recuperación que ha proporcionado es incorrecta.",
"TRY AGAIN": "INTENTAR DE NUEVO",
"Tap each word in the correct order.": "Toque cada palabra en el orden correcto.",
"Addresses": "Direcciones",
"Could not update wallet": "No se pudo actualizar billetera",
"Each wallet (except for ETH/ERC20) can generate billions of addresses from your 12-word recovery phrase. A new address is automatically generated and shown each time you receive a payment.": "Cada billetera (excepto las ETH/ERC20) puede generar miles de millones de direcciones a partir de su frase de recuperación de 12 palabras. Una nueva dirección se genera automáticamente y se muestra cada vez que recibe un pago.",
"It's a good idea to avoid reusing addresses - this both protects your privacy and keeps your bitcoins secure against hypothetical attacks by quantum computers.": "Es una buena idea evitar reutilizar las direcciones - esto protege su privacidad y mantiene sus bitcoins seguros contra hipotéticos ataques por computadoras cuánticas.",
"Scan Addresses for Funds": "Buscar direcciones con fondos",
"View all addresses": "Ver todas las direcciones",
"Wallet Inputs": "Inputs de la billetera",
"Total wallet inputs": "Total de inputs de la billetera",
"Low amount inputs": "Importes bajos de los inputs",
"Approximate Bitcoin network fee to transfer wallet's balance (with normal priority)": "Comisión aproximada de la red de Bitcoin para transferir el balance de la billetera (con prioridad normal)",
Expand Down Expand Up @@ -1070,6 +1081,8 @@
"Verification Required": "Verification Required",
"To complete this payment please verify your account.": "To complete this payment please verify your account.",
"Verify": "Verify",
"Connect Your BitPay ID": "Conecte su ID de BitPay",
"To complete this payment, please login with your BitPay ID.": "Para completar este pago, inicie sesión con su ID de BitPay.",
"Session request failed or rejected. Please try again by refreshing the QR code.": "Solicitud de sesión fallida o rechazada. Vuelva a intentarlo actualizando el código QR.",
"20 Wallet limit from the same coin and network has been reached.": "Se alcanzó el límite de 20 billeteras de la misma moneda y red.",
"High": "Alta",
Expand Down
56 changes: 56 additions & 0 deletions src/components/list/InputsRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, {memo, useState} from 'react';
import styled from 'styled-components/native';
import {ActiveOpacity, Column} from '../styled/Containers';
import {RowContainer} from '../styled/Containers';
import {H5, ListItemSubText} from '../styled/Text';
import haptic from '../haptic-feedback/haptic';
import Checkbox from '../checkbox/Checkbox';
import {Utxo} from '../../store/wallet/wallet.models';

interface Props {
item: Utxo;
unitCode?: string;
emit: (item: Utxo, index: number) => void;
index: number;
}

const CheckBoxContainer = styled.View`
flex-direction: column;
justify-content: center;
`;

const InputColumn = styled(Column)`
margin-left: 16px;
`;

const InputSelectionRow = ({item, unitCode, emit, index}: Props) => {
const {amount, address, checked: initialCheckValue} = item;

const [checked, setChecked] = useState(!!initialCheckValue);
const toggle = (): void => {
setChecked(!checked);
haptic('impactLight');
emit({...item, ...{checked: !checked}}, index);
};

return (
<RowContainer
activeOpacity={ActiveOpacity}
onPress={toggle}
style={{paddingLeft: 0, paddingRight: 0}}>
<CheckBoxContainer>
<Checkbox checked={checked} onPress={toggle} />
</CheckBoxContainer>
<InputColumn>
<H5>
{amount} {unitCode?.toUpperCase()}{' '}
</H5>
<ListItemSubText numberOfLines={1} ellipsizeMode={'middle'}>
{address}
</ListItemSubText>
</InputColumn>
</RowContainer>
);
};

export default memo(InputSelectionRow);
14 changes: 14 additions & 0 deletions src/navigation/wallet/WalletStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ import PayProConfirmTwoFactor, {
PayProConfirmTwoFactorParamList,
} from './screens/send/confirm/PayProConfirmTwoFactor';
import {useTranslation} from 'react-i18next';
import SendToOptions, {SendToOptionsParamList} from './screens/SendToOptions';
import SelectInputs, {SelectInputsParamList} from './screens/SelectInputs';

export type WalletStackParamList = {
CurrencySelection: CurrencySelectionParamList;
Expand Down Expand Up @@ -128,6 +130,8 @@ export type WalletStackParamList = {
AllAddresses: AllAddressesParamList;
PriceCharts: PriceChartsParamList;
ClearEncryptPassword: ClearEncryptPasswordParamList;
SendToOptions: SendToOptionsParamList;
SelectInputs: SelectInputsParamList;
};

export enum WalletScreens {
Expand Down Expand Up @@ -172,6 +176,8 @@ export enum WalletScreens {
ALL_ADDRESSES = 'AllAddresses',
PRICE_CHARTS = 'PriceCharts',
CLEAR_ENCRYPT_PASSWORD = 'ClearEncryptPassword',
SEND_TO_OPTIONS = 'SendToOptions',
SELECT_INPUTS = 'SelectInputs',
}

const Wallet = createStackNavigator<WalletStackParamList>();
Expand Down Expand Up @@ -402,6 +408,14 @@ const WalletStack = () => {
name={WalletScreens.CLEAR_ENCRYPT_PASSWORD}
component={ClearEncryptPassword}
/>
<Wallet.Screen
name={WalletScreens.SEND_TO_OPTIONS}
component={SendToOptions}
/>
<Wallet.Screen
name={WalletScreens.SELECT_INPUTS}
component={SelectInputs}
/>
</Wallet.Navigator>
</>
);
Expand Down
79 changes: 79 additions & 0 deletions src/navigation/wallet/components/AddressCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react';
import styled from 'styled-components/native';
import {BaseText, H7} from '../../../components/styled/Text';
import {LightBlack, NeutralSlate} from '../../../styles/colors';
import {
ActiveOpacity,
Column,
Row,
} from '../../../components/styled/Containers';
import {TxDetailsSendingTo} from '../../../store/wallet/wallet.models';
import {CurrencyImage} from '../../../components/currency-image/CurrencyImage';
import ContactIcon from '../../tabs/contacts/components/ContactIcon';

interface AddressCardComponentProps {
recipient: TxDetailsSendingTo;
}

const ListCard = styled.TouchableOpacity`
background-color: ${({theme: {dark}}) => (dark ? LightBlack : NeutralSlate)};
border-radius: 12px;
margin: 6px 0;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 15px;
height: 75px;
`;

const RecipientAmount = styled(BaseText)`
font-style: normal;
font-weight: 500;
font-size: 14px;
line-height: 19px;
`;

const ContactImageContainer = styled.View`
height: 20px;
width: 20px;
justify-content: center;
align-self: center;
border-radius: 8px;
margin-right: 8px;
`;

const AddressCard: React.FC<AddressCardComponentProps> = ({recipient}) => {
return (
<ListCard activeOpacity={ActiveOpacity} style={{height: 59, margin: 0}}>
<Row style={{alignItems: 'center', justifyContent: 'space-between'}}>
<Row style={{alignItems: 'center', justifyContent: 'flex-start'}}>
<ContactImageContainer>
{recipient.recipientType === 'contact' ? (
<ContactIcon
name={recipient.recipientName || recipient.recipientAddress}
coin={recipient.recipientCoin!}
size={30}
/>
) : (
<CurrencyImage img={recipient.img} size={30} />
)}
</ContactImageContainer>
<H7
style={{marginLeft: 8}}
numberOfLines={1}
ellipsizeMode={'middle'}>
{recipient.recipientAddress}
</H7>
</Row>
<Column style={{alignItems: 'flex-end'}}>
<RecipientAmount>{recipient.recipientAmountStr}</RecipientAmount>
{recipient.recipientAltAmountStr ? (
<H7>{recipient.recipientAltAmountStr}</H7>
) : null}
</Column>
</Row>
</ListCard>
);
};

export default AddressCard;
47 changes: 47 additions & 0 deletions src/navigation/wallet/components/AmountModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import styled from 'styled-components/native';
import {gestureHandlerRootHOC} from 'react-native-gesture-handler';
import {Black, White} from '../../../styles/colors';
import SheetModal from '../../../components/modal/base/sheet/SheetModal';
import Amount from '../screens/Amount';

const AmountContainer = styled.View`
flex: 1;
background-color: ${({theme: {dark}}) => (dark ? Black : White)};
`;

interface AmountModalProps {
isVisible: boolean;
onDismiss: (amount?: number) => void;
opts: {
context?: string;
hideSendMax?: boolean;
currencyAbbreviation?: string;
};
}

const AmountModalWrapper = gestureHandlerRootHOC(props => {
return <AmountContainer>{props.children}</AmountContainer>;
});

const AmountModal: React.FC<AmountModalProps> = ({
isVisible,
onDismiss,
opts,
}) => {
return (
<SheetModal isVisible={isVisible} onBackdropPress={onDismiss}>
<AmountModalWrapper>
<Amount
useAsModal={true}
onDismiss={onDismiss}
hideSendMaxProp={opts.hideSendMax}
contextProp={opts.context}
currencyAbbreviationProp={opts.currencyAbbreviation}
/>
</AmountModalWrapper>
</SheetModal>
);
};

export default AmountModal;
3 changes: 2 additions & 1 deletion src/navigation/wallet/components/OptionsSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
SheetParams,
} from '../../../components/styled/Containers';
import {Platform, Image, ImageSourcePropType} from 'react-native';
import {Black, Slate} from '../../../styles/colors';
import {Action, Black, Slate, White} from '../../../styles/colors';

const OptionsTitleContainer = styled.View`
margin-bottom: 25px;
Expand Down Expand Up @@ -37,6 +37,7 @@ const OptionTitleText = styled(BaseText)`
font-weight: 500;
font-size: 14px;
line-height: 19px;
color: ${({theme: {dark}}) => (dark ? White : Action)};
`;

const OptionDescriptionText = styled(BaseText)`
Expand Down
Loading

0 comments on commit b370bb4

Please sign in to comment.