Skip to content

Commit bbe9d5f

Browse files
committed
Add address list to receive screen
Users can now see all their generated addresses in a scrollable list below the QR code. Features: - Shows all addresses numbered (#1, #2, etc.) - Tap an address to select it (updates QR code and display) - Active address highlighted with green dot - Copy button on each address row - Long press to copy - 'New Address' generates and selects the next HD address
1 parent 75fc35f commit bbe9d5f

1 file changed

Lines changed: 108 additions & 21 deletions

File tree

app/(tabs)/receive.tsx

Lines changed: 108 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,60 @@
11
/**
22
* Receive screen.
3-
* Displays current receive address with QR code and copy action.
3+
* Displays current receive address with QR code, copy action,
4+
* and a scrollable list of all generated addresses.
45
*/
56

6-
import { useCallback } from "react";
7-
import { View, Text, Pressable, Alert, ActivityIndicator } from "react-native";
7+
import { useCallback, useState } from "react";
8+
import {
9+
View,
10+
Text,
11+
Pressable,
12+
Alert,
13+
ActivityIndicator,
14+
ScrollView,
15+
FlatList,
16+
} from "react-native";
817
import { SafeAreaView } from "react-native-safe-area-context";
918
import * as Clipboard from "expo-clipboard";
1019
import QRCode from "react-native-qrcode-svg";
1120
import { useWalletStore } from "../../src/wallet/wallet-store";
1221
import { Button } from "../../src/ui/components/Button";
1322

23+
function truncateAddress(address: string): string {
24+
if (address.length <= 16) return address;
25+
return `${address.slice(0, 10)}...${address.slice(-8)}`;
26+
}
27+
1428
export default function ReceiveScreen() {
1529
const receiveAddress = useWalletStore((s) => s.currentReceiveAddress);
30+
const addresses = useWalletStore((s) => s.addresses);
1631
const getNewAddress = useWalletStore((s) => s.getNewAddress);
1732

33+
const [selectedAddress, setSelectedAddress] = useState<string | null>(null);
34+
const displayAddress = selectedAddress ?? receiveAddress;
35+
1836
const handleCopy = useCallback(async () => {
19-
await Clipboard.setStringAsync(receiveAddress);
37+
await Clipboard.setStringAsync(displayAddress);
2038
Alert.alert("Copied", "Address copied to clipboard");
21-
}, [receiveAddress]);
39+
}, [displayAddress]);
2240

2341
const handleNewAddress = useCallback(() => {
24-
getNewAddress();
42+
const addr = getNewAddress();
43+
setSelectedAddress(addr);
2544
}, [getNewAddress]);
2645

46+
const handleSelectAddress = useCallback(
47+
(address: string) => {
48+
setSelectedAddress(address);
49+
},
50+
[],
51+
);
52+
53+
const handleCopyAddress = useCallback(async (address: string) => {
54+
await Clipboard.setStringAsync(address);
55+
Alert.alert("Copied", "Address copied to clipboard");
56+
}, []);
57+
2758
if (!receiveAddress) {
2859
return (
2960
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}>
@@ -39,40 +70,45 @@ export default function ReceiveScreen() {
3970

4071
return (
4172
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}>
42-
<View className="flex-1 items-center px-6 pt-8">
73+
<ScrollView
74+
className="flex-1"
75+
contentContainerClassName="px-6 pt-6 pb-8"
76+
>
4377
{/* Title */}
44-
<Text className="text-white text-xl font-bold mb-2">
78+
<Text className="text-white text-xl font-bold mb-1 text-center">
4579
Receive FAIR
4680
</Text>
47-
<Text className="text-fair-muted text-sm mb-8 text-center">
81+
<Text className="text-fair-muted text-sm mb-6 text-center">
4882
Share this address to receive FairCoin
4983
</Text>
5084

5185
{/* QR Code */}
52-
<View className="w-56 h-56 items-center justify-center mb-6">
53-
<QRCode
54-
value={`faircoin:${receiveAddress}`}
55-
size={200}
56-
color="#9ffb50"
57-
backgroundColor="transparent"
58-
/>
86+
<View className="items-center mb-6">
87+
<View className="w-56 h-56 items-center justify-center">
88+
<QRCode
89+
value={`faircoin:${displayAddress}`}
90+
size={200}
91+
color="#9ffb50"
92+
backgroundColor="transparent"
93+
/>
94+
</View>
5995
</View>
6096

61-
{/* Address display */}
97+
{/* Selected address display */}
6298
<Pressable
63-
className="bg-fair-dark-light border border-fair-border rounded-xl p-4 w-full mb-2"
99+
className="bg-fair-dark-light border border-fair-border rounded-xl p-4 w-full mb-4"
64100
onPress={handleCopy}
65101
>
66102
<Text
67103
className="text-white text-sm text-center font-mono"
68104
selectable
69105
>
70-
{receiveAddress}
106+
{displayAddress}
71107
</Text>
72108
</Pressable>
73109

74110
{/* Actions */}
75-
<View className="w-full gap-3">
111+
<View className="w-full gap-3 mb-8">
76112
<Button
77113
title="Copy Address"
78114
onPress={handleCopy}
@@ -84,7 +120,58 @@ export default function ReceiveScreen() {
84120
variant="outline"
85121
/>
86122
</View>
87-
</View>
123+
124+
{/* All addresses */}
125+
{addresses.length > 0 ? (
126+
<>
127+
<Text className="text-fair-muted text-xs font-semibold uppercase tracking-wider mb-3 px-1">
128+
Your Addresses ({addresses.length})
129+
</Text>
130+
<View className="bg-fair-dark-light rounded-xl overflow-hidden">
131+
{addresses.map((address, idx) => {
132+
const isActive = address === displayAddress;
133+
return (
134+
<Pressable
135+
key={`${idx}-${address}`}
136+
className={`flex-row items-center justify-between px-4 py-3 ${
137+
idx < addresses.length - 1 ? "border-b border-fair-border" : ""
138+
} ${isActive ? "bg-fair-green/5" : ""}`}
139+
onPress={() => handleSelectAddress(address)}
140+
onLongPress={() => handleCopyAddress(address)}
141+
>
142+
<View className="flex-1 mr-3">
143+
<View className="flex-row items-center">
144+
{isActive ? (
145+
<View className="w-2 h-2 rounded-full bg-fair-green mr-2" />
146+
) : null}
147+
<Text
148+
className={`text-xs font-mono ${
149+
isActive ? "text-fair-green" : "text-white"
150+
}`}
151+
>
152+
{truncateAddress(address)}
153+
</Text>
154+
</View>
155+
<Text className="text-fair-muted text-xs mt-0.5">
156+
#{idx + 1}
157+
</Text>
158+
</View>
159+
<Pressable
160+
className="bg-fair-dark border border-fair-border rounded-lg px-3 py-1.5"
161+
onPress={() => handleCopyAddress(address)}
162+
>
163+
<Text className="text-fair-green text-xs">Copy</Text>
164+
</Pressable>
165+
</Pressable>
166+
);
167+
})}
168+
</View>
169+
<Text className="text-fair-muted text-xs mt-2 text-center">
170+
Tap to select, long press to copy
171+
</Text>
172+
</>
173+
) : null}
174+
</ScrollView>
88175
</SafeAreaView>
89176
);
90177
}

0 commit comments

Comments
 (0)