Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions components/DetailRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import { useTheme } from './themes';
import CopyIcon from './icons/CopyIcon';
import { ClashFont } from '../constants/fonts';
import loc from '../loc';

interface DetailRowProps {
label: string;
value: string;
mono?: boolean;
onCopy?: () => void;
copied?: boolean;
accessibilityLabel?: string;
}

const DetailRow: React.FC<DetailRowProps> = ({ label, value, mono, onCopy, copied, accessibilityLabel }) => {
const { colors } = useTheme();
const stylesHook = StyleSheet.create({
label: { color: colors.textPrimary },
value: { color: colors.textPrimary },
});
return (
<View style={styles.row}>
<View style={styles.head}>
<Text style={[styles.label, stylesHook.label]}>{label}</Text>
{onCopy && (
<Pressable
accessibilityRole="button"
accessibilityLabel={accessibilityLabel ?? loc.transactions.details_copy}
hitSlop={10}
onPress={onCopy}
style={styles.copyBtn}
>
<CopyIcon size={16} color={copied ? colors.brandPrimary : colors.chevron} />
</Pressable>
)}
</View>
<Text style={[mono ? styles.valueMono : styles.value, stylesHook.value]}>{value}</Text>
</View>
);
};

const styles = StyleSheet.create({
row: {
gap: 4,
paddingVertical: 8,
},
head: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
label: {
fontFamily: ClashFont.medium,
fontSize: 14,
lineHeight: 26,
},
value: {
fontFamily: ClashFont.regular,
fontSize: 14,
lineHeight: 20,
},
valueMono: {
fontFamily: ClashFont.regular,
fontSize: 14,
lineHeight: 26,
},
copyBtn: {
width: 24,
height: 24,
alignItems: 'center',
justifyContent: 'center',
},
});

export default DetailRow;
2 changes: 1 addition & 1 deletion components/TransactionListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = memo(
if (renderHighlightedText) {
pop();
}
navigate('TransactionStatus', { hash: item.hash, walletID });
navigate('TransactionDetails', { tx: item, hash: item.hash, walletID });
}
}, [item, renderHighlightedText, navigate, walletID, customOnPress]);

Expand Down
14 changes: 14 additions & 0 deletions components/icons/ExternalLinkIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
import { IconProps } from './types';

const ExternalLinkIcon: React.FC<IconProps> = ({ color = 'white', size = 24 }) => (
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
<Path
d="M11 6C11.2652 6 11.5196 6.10536 11.7071 6.29289C11.8946 6.48043 12 6.73478 12 7C12 7.26522 11.8946 7.51957 11.7071 7.70711C11.5196 7.89464 11.2652 8 11 8H5V19H16V13C16 12.7348 16.1054 12.4804 16.2929 12.2929C16.4804 12.1054 16.7348 12 17 12C17.2652 12 17.5196 12.1054 17.7071 12.2929C17.8946 12.4804 18 12.7348 18 13V19C18 19.5304 17.7893 20.0391 17.4142 20.4142C17.0391 20.7893 16.5304 21 16 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V8C3 7.46957 3.21071 6.96086 3.58579 6.58579C3.96086 6.21071 4.46957 6 5 6H11ZM20 3C20.2652 3 20.5196 3.10536 20.7071 3.29289C20.8946 3.48043 21 3.73478 21 4V9C21 9.26522 20.8946 9.51957 20.7071 9.70711C20.5196 9.89464 20.2652 10 20 10C19.7348 10 19.4804 9.89464 19.2929 9.70711C19.1054 9.51957 19 9.26522 19 9V6.414L10.707 14.707C10.5184 14.8892 10.2658 14.99 10.0036 14.9877C9.7414 14.9854 9.49059 14.8802 9.30518 14.6948C9.11977 14.5094 9.0146 14.2586 9.01233 13.9964C9.01005 13.7342 9.11084 13.4816 9.293 13.293L17.586 5H15C14.7348 5 14.4804 4.89464 14.2929 4.70711C14.1054 4.51957 14 4.26522 14 4C14 3.73478 14.1054 3.48043 14.2929 3.29289C14.4804 3.10536 14.7348 3 15 3H20Z"
fill={color}
/>
</Svg>
);

export default ExternalLinkIcon;
12 changes: 6 additions & 6 deletions components/themes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const tokens = {
copyHint: same(palette.gray450), // "tap to copy" icon + label
progressTrack: same('#EAECF0'),
buttonBorder: same('#EBEBEB'),
textPrimary: same('#1A1A1A'), // titles, primary copy
textPrimary: pair('#1A1A1A', palette.white), // titles, primary copy
textSecondary: same('#8E8E93'), // subtitles, privacy copy
textMeta: same('#92929B'), // ETA / "%" meta text
textMuted: same('#7B7A7E'), // card row labels
Expand Down Expand Up @@ -137,18 +137,18 @@ const tokens = {
cardBackground: pair('#FDFCFE', '#1A1A1A'),

// --- Send redesign tokens. Ones using lightOnly() still need real dark values (see todoDark, #3). ---
fieldBackground: lightOnly(palette.gray50), // Address / Note field background
amountMeta: lightOnly('#9B9BA5'), // BTC unit, fiat estimate, slow/medium ETA
fieldBackground: pair(palette.gray50, '#1E1E1E'), // Address / Note field background
amountMeta: pair('#9B9BA5', '#AEAEB2'), // BTC unit, fiat estimate, slow/medium ETA
amountPlaceholder: lightOnly('rgba(0,0,0,0.32)'), // AmountHero empty/placeholder digits
scrim: lightOnly('rgba(10, 13, 19, 0.8)'), // Success bottom-sheet backdrop
ctaDisabled: lightOnly(palette.gray450), // disabled primary button background
feeCardBorder: lightOnly('#E6E6E8'), // unselected fee card border
feeCardSelectedBorder: lightOnly('#B9BAF9'), // selected fee card border
useMaxBorder: lightOnly('#E8E4FA'), // "Use Max" pill border
useMaxText: lightOnly('#6E55E0'), // "Use Max" pill text
copyButtonBorder: lightOnly(palette.gray200), // Confirm copy-button border
divider: lightOnly(palette.gray200), // Confirm section dividers
summaryBorder: lightOnly(palette.gray200), // SendDetails fee summary card border
copyButtonBorder: pair(palette.gray200, palette.gray800), // Confirm copy-button border
divider: pair(palette.gray200, palette.gray850), // Confirm section dividers
summaryBorder: pair(palette.gray200, palette.gray850), // SendDetails fee summary card border
transactionCardBorder: pair(palette.gray200, palette.gray850),
txIconHaloBorder: pair(palette.violet100, palette.violet850),
incomingIconBackground: pair('#E7E6F5', '#322361'),
Expand Down
13 changes: 0 additions & 13 deletions loc/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@
"cancel_explain": "We will replace this transaction with one that pays you and has higher fees. This effectively cancels the current transaction. This is called RBF—Replace by Fee.",
"cancel_no": "This transaction is not replaceable.",
"cancel_title": "Cancel this transaction (RBF)",
"transaction_loading_error": "There was an issue loading the transaction. Please try again later.",
"transaction_not_available": "Transaction not available",
"confirmations_lowercase": "{confirmations} confirmations",
"expand_note": "Expand Note",
"cpfp_create": "Create",
"cpfp_exp": "We will create another transaction that spends your unconfirmed transaction. The total fee will be higher than the original transaction fee, so it should be mined faster. This is called CPFP—Child Pays for Parent.",
Expand All @@ -243,27 +240,17 @@
"details_copy": "Copy",
"details_copy_note": "Copy Note",
"details_copy_txid": "Copy Transaction ID",
"details_from": "Input",
"details_inputs": "Inputs",
"details_outputs": "Outputs",
"details_received": "Received",
"details_title": "Transaction",
"details_to": "Output",
"list_conf": "Conf: {number}",
"pending": "Pending",
"pending_with_amount": "Pending {amt1} ({amt2})",
"received_with_amount": "+{amt1} ({amt2})",
"eta_10m": "ETA: In ~10 minutes",
"eta_3h": "ETA: In ~3 hours",
"eta_1d": "ETA: In ~1 day",
"view_wallet": "View {walletLabel}",
"list_title": "Transactions",
"transaction": "Transaction",
"rbf_explain": "We will replace this transaction with one with a higher fee so that it will be mined faster. This is called RBF—Replace by Fee.",
"rbf_title": "Bump Fee (RBF)",
"status_bump": "Bump Fee",
"status_cancel": "Cancel Transaction",
"txid": "Transaction ID",
"updating": "Updating..."
},
"wallets": {
Expand Down
20 changes: 0 additions & 20 deletions navigation/DetailViewScreensStack.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useMemo } from 'react';
import { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import HeaderRightButton from '../components/HeaderRightButton';
import navigationStyle, { CloseButtonPosition } from '../components/navigationStyle';
import { useTheme } from '../components/themes';
import loc from '../loc';
Expand All @@ -10,7 +9,6 @@ import CPFP from '../screen/transactions/CPFP';
import TransactionDetails from '../screen/transactions/TransactionDetails';
import RBFBumpFee from '../screen/transactions/RBFBumpFee';
import RBFCancel from '../screen/transactions/RBFCancel';
import TransactionStatus from '../screen/transactions/TransactionStatus';
import WalletsList from '../screen/wallets/WalletsList';
import { DetailViewStack } from './index';
import SettingsButton from '../components/icons/SettingsButton';
Expand All @@ -36,7 +34,6 @@ import OnboardingStack from './OnboardingStack';
const DetailViewStackScreensStack = () => {
const theme = useTheme();
const { sizeClass } = useSizeClass();
const DetailButton = useMemo(() => <HeaderRightButton testID="DetailButton" disabled={true} title={loc.send.create_details} />, []);
const RightBarButtons = useMemo(() => <SettingsButton />, []);

const walletListScreenOptions = useMemo<NativeStackNavigationOptions>(() => {
Expand Down Expand Up @@ -80,23 +77,6 @@ const DetailViewStackScreensStack = () => {
headerTitle: loc.transactions.details_title,
})(theme)}
/>
<DetailViewStack.Screen
name="TransactionStatus"
component={TransactionStatus}
initialParams={{
hash: undefined,
walletID: undefined,
}}
options={navigationStyle({
statusBarStyle: 'auto',
headerStyle: {
backgroundColor: theme.colors.background,
},
headerTitle: '',
headerRight: () => DetailButton,
headerBackButtonDisplayMode: 'default',
})(theme)}
/>
<DetailViewStack.Screen name="CPFP" component={CPFP} options={navigationStyle({ title: loc.transactions.cpfp_title })(theme)} />
<DetailViewStack.Screen
name="RBFBumpFee"
Expand Down
2 changes: 1 addition & 1 deletion navigation/DetailViewStackParamList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type DetailViewStackParamList = {
UnlockWithScreen: undefined;
WalletsList: { onBarScanned?: string };
TransactionDetails: { tx: Transaction; hash: string; walletID: string };
TransactionStatus: { hash: string; walletID?: string };

CPFP: {
wallet: TWallet | null;
txid: string;
Expand Down
12 changes: 10 additions & 2 deletions navigation/SendDetailsStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,16 @@ const SendDetailsStack = () => {
)(theme)}
initialParams={{ isEditable: true, feeUnit: BitcoinUnit.BTC, amountUnit: BitcoinUnit.BTC }} // Correctly typed now
/>
<Stack.Screen name="SelectFee" component={SelectFeeScreen} options={navigationStyle({ title: loc.send.network_fee_header })(theme)} />
<Stack.Screen name="Confirm" component={ConfirmComponent} options={navigationStyle({ title: loc.send.confirm_header })(theme)} />
<Stack.Screen
name="SelectFee"
component={SelectFeeScreen}
options={navigationStyle({ title: loc.send.network_fee_header }, withBackChevron)(theme)}
/>
<Stack.Screen
name="Confirm"
component={ConfirmComponent}
options={navigationStyle({ title: loc.send.confirm_header }, withBackChevron)(theme)}
/>
<Stack.Screen
name="PsbtWithHardwareWallet"
component={PsbtWithHardwareWalletComponent}
Expand Down
67 changes: 6 additions & 61 deletions screen/send/Confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { useStorage } from '../../hooks/context/useStorage';
import { useSettings } from '../../hooks/context/useSettings';
import AmountHero from '../../components/AmountHero';
import CopyIcon from '../../components/icons/CopyIcon';
import DetailRow from '../../components/DetailRow';
import SendIcon from '../../components/icons/SendIcon';
import { ClashFont } from '../../constants/fonts';
import { computeTotalSats } from '../../helpers/send/format';
Expand Down Expand Up @@ -57,34 +57,6 @@ const reducer = (state: State, action: Action): State => {
type ConfirmRouteProp = RouteProp<SendDetailsStackParamList, 'Confirm'>;
type ConfirmNavigationProp = NativeStackNavigationProp<SendDetailsStackParamList, 'Confirm'>;

const ConfirmDetailRow: React.FC<{ label: string; value: string; mono?: boolean; onCopy?: () => void; copied?: boolean }> = ({
label,
value,
mono,
onCopy,
copied,
}) => {
const { colors } = useTheme();
const stylesHook = StyleSheet.create({
label: { color: colors.textPrimary },
value: { color: colors.textPrimary },
copyBtn: { backgroundColor: colors.white, borderColor: colors.copyButtonBorder },
});
return (
<View style={styles.detailRow}>
<View style={styles.detailHead}>
<Text style={[styles.detailLabel, stylesHook.label]}>{label}</Text>
{onCopy && (
<Pressable accessibilityRole="button" onPress={onCopy} style={[styles.copyBtn, stylesHook.copyBtn]}>
<CopyIcon size={16} color={copied ? colors.brandPrimary : colors.chevron} />
</Pressable>
)}
</View>
<Text style={[mono ? styles.detailMono : styles.detailValue, stylesHook.value]}>{value}</Text>
</View>
);
};

const Confirm: React.FC = () => {
const { wallets, fetchAndSaveWalletTransactions } = useStorage();
const { isElectrumDisabled } = useSettings();
Expand Down Expand Up @@ -208,21 +180,23 @@ const Confirm: React.FC = () => {

<View style={styles.detailsGroup}>
<View>
<ConfirmDetailRow
<DetailRow
label={loc.send.onchain_address_derived}
value={recipient?.address ?? ''}
mono
copied={copiedAddr}
onCopy={() => copy(recipient?.address ?? '', setCopiedAddr)}
accessibilityLabel={loc.transactions.details_copy}
/>
<View style={styles.lightDivider} />

<ConfirmDetailRow
<DetailRow
label={loc.send.transaction_id}
value={txid}
mono
copied={copiedTxid}
onCopy={() => copy(txid, setCopiedTxid)}
accessibilityLabel={loc.transactions.details_copy_txid}
/>
<View style={styles.lightDivider} />
</View>
Expand Down Expand Up @@ -296,36 +270,7 @@ const styles = StyleSheet.create({
detailsGroup: {
marginTop: -10,
},
detailRow: {
gap: 4,
paddingVertical: 8,
},
detailHead: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
detailLabel: {
fontFamily: ClashFont.medium,
fontSize: 14,
lineHeight: 26,
},
detailValue: {
fontFamily: ClashFont.regular,
fontSize: 14,
lineHeight: 20,
},
detailMono: {
fontFamily: ClashFont.regular,
fontSize: 14,
lineHeight: 26,
},
copyBtn: {
width: 24,
height: 24,
alignItems: 'center',
justifyContent: 'center',
},

summaryRow: {
flexDirection: 'row',
justifyContent: 'space-between',
Expand Down
Loading
Loading