Skip to content

Commit 8f54cf8

Browse files
committed
Edge-to-edge scrolling: content scrolls behind notch/status bar
Replaced SafeAreaView wrappers with useSafeAreaInsets() + paddingTop on ScrollView/FlatList contentContainerStyle across all scrollable screens. Content starts below the safe area but scrolls behind the notch for a more immersive feel. Non-scrollable screens (onboarding, lock, PIN) keep their SafeAreaView for fixed layout. Changed: index, send, receive, settings, masternode, wallets, transaction detail, coin-control, contacts, export-key (10 files)
1 parent db7fcde commit 8f54cf8

10 files changed

Lines changed: 66 additions & 47 deletions

File tree

app/(tabs)/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { useCallback, useState } from "react";
77
import { View, Text, ScrollView, RefreshControl } from "react-native";
8-
import { SafeAreaView } from "react-native-safe-area-context";
8+
import { useSafeAreaInsets } from "react-native-safe-area-context";
99
import { useFocusEffect } from "expo-router";
1010
import { useWalletStore } from "../../src/wallet/wallet-store";
1111
import { SyncStatus } from "../../src/ui/components/SyncStatus";
@@ -47,6 +47,7 @@ function formatChange(change: number | null): {
4747
}
4848

4949
export default function HomeScreen() {
50+
const insets = useSafeAreaInsets();
5051
const balance = useWalletStore((s) => s.balance);
5152
const isSyncing = useWalletStore((s) => s.isSyncing);
5253
const syncProgress = useWalletStore((s) => s.syncProgress);
@@ -84,10 +85,11 @@ export default function HomeScreen() {
8485
const change = price ? formatChange(price.change24h) : null;
8586

8687
return (
87-
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}>
88+
<View className="flex-1 bg-fair-dark">
8889
<ScrollView
8990
className="flex-1"
9091
contentContainerClassName="pb-8"
92+
contentContainerStyle={{ paddingTop: insets.top }}
9193
refreshControl={
9294
<RefreshControl
9395
refreshing={loading}
@@ -173,6 +175,6 @@ export default function HomeScreen() {
173175
)}
174176
</View>
175177
</ScrollView>
176-
</SafeAreaView>
178+
</View>
177179
);
178180
}

app/(tabs)/receive.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
FlatList,
1616
Share,
1717
} from "react-native";
18-
import { SafeAreaView } from "react-native-safe-area-context";
18+
import { useSafeAreaInsets } from "react-native-safe-area-context";
1919
import * as Clipboard from "expo-clipboard";
2020
import QRCode from "react-native-qrcode-svg";
2121
import { useWalletStore } from "../../src/wallet/wallet-store";
@@ -28,6 +28,7 @@ function truncateAddress(address: string): string {
2828
}
2929

3030
export default function ReceiveScreen() {
31+
const insets = useSafeAreaInsets();
3132
const receiveAddress = useWalletStore((s) => s.currentReceiveAddress);
3233
const addresses = useWalletStore((s) => s.addresses);
3334
const getNewAddress = useWalletStore((s) => s.getNewAddress);
@@ -67,22 +68,23 @@ export default function ReceiveScreen() {
6768

6869
if (!receiveAddress) {
6970
return (
70-
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}>
71+
<View className="flex-1 bg-fair-dark" style={{ paddingTop: insets.top }}>
7172
<View className="flex-1 items-center justify-center px-6">
7273
<ActivityIndicator size="large" color="#9ffb50" />
7374
<Text className="text-fair-muted text-sm mt-4">
7475
Generating receive address...
7576
</Text>
7677
</View>
77-
</SafeAreaView>
78+
</View>
7879
);
7980
}
8081

8182
return (
82-
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}>
83+
<View className="flex-1 bg-fair-dark">
8384
<ScrollView
8485
className="flex-1"
8586
contentContainerClassName="px-6 pt-6 pb-8"
87+
contentContainerStyle={{ paddingTop: insets.top }}
8688
>
8789
{/* Title */}
8890
<Text className="text-white text-xl font-bold mb-1 text-center">
@@ -187,6 +189,6 @@ export default function ReceiveScreen() {
187189
</>
188190
) : null}
189191
</ScrollView>
190-
</SafeAreaView>
192+
</View>
191193
);
192194
}

app/(tabs)/send.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
Modal,
1414
Alert,
1515
} from "react-native";
16-
import { SafeAreaView } from "react-native-safe-area-context";
16+
import { useSafeAreaInsets } from "react-native-safe-area-context";
1717
import { useLocalSearchParams, useRouter } from "expo-router";
1818
import * as Clipboard from "expo-clipboard";
1919
import {
@@ -70,6 +70,7 @@ function parseFairToSats(input: string): bigint | null {
7070
}
7171

7272
export default function SendScreen() {
73+
const insets = useSafeAreaInsets();
7374
const router = useRouter();
7475
const balance = useWalletStore((s) => s.balance);
7576
const sendTransaction = useWalletStore((s) => s.sendTransaction);
@@ -81,7 +82,7 @@ export default function SendScreen() {
8182
// Watch-only wallets cannot send transactions
8283
if (isWatchOnly) {
8384
return (
84-
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}>
85+
<View className="flex-1 bg-fair-dark" style={{ paddingTop: insets.top }}>
8586
<View className="flex-1 items-center justify-center px-8">
8687
<Text className="text-fair-muted text-4xl mb-4">{"\uD83D\uDD12"}</Text>
8788
<Text className="text-white text-xl font-bold mb-2 text-center">
@@ -92,7 +93,7 @@ export default function SendScreen() {
9293
with a recovery phrase to enable sending.
9394
</Text>
9495
</View>
95-
</SafeAreaView>
96+
</View>
9697
);
9798
}
9899

@@ -257,12 +258,13 @@ export default function SendScreen() {
257258
}, []);
258259

259260
return (
260-
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}
261+
<View className="flex-1 bg-fair-dark"
261262
onLayout={loadRecentRecipients}
262263
>
263264
<ScrollView
264265
className="flex-1"
265266
contentContainerClassName="px-6 pt-4 pb-8"
267+
contentContainerStyle={{ paddingTop: insets.top }}
266268
keyboardShouldPersistTaps="handled"
267269
>
268270
{/* Recent recipients */}
@@ -511,6 +513,6 @@ export default function SendScreen() {
511513
onClose={handleCloseContactPicker}
512514
/>
513515
</ScrollView>
514-
</SafeAreaView>
516+
</View>
515517
);
516518
}

app/(tabs)/settings.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
Alert,
1515
} from "react-native";
1616
import { useRouter, useFocusEffect } from "expo-router";
17-
import { SafeAreaView } from "react-native-safe-area-context";
17+
import { useSafeAreaInsets } from "react-native-safe-area-context";
1818
import * as LocalAuthentication from "expo-local-authentication";
1919
import { useWalletStore } from "../../src/wallet/wallet-store";
2020
import {
@@ -302,6 +302,7 @@ function RecoveryModal({ visible, mnemonic, onDismiss }: RecoveryModalProps) {
302302
// ---------------------------------------------------------------------------
303303

304304
export default function SettingsScreen() {
305+
const insets = useSafeAreaInsets();
305306
const router = useRouter();
306307
const network = useWalletStore((s) => s.network);
307308
const connectedPeers = useWalletStore((s) => s.connectedPeers);
@@ -549,10 +550,11 @@ export default function SettingsScreen() {
549550
}, []);
550551

551552
return (
552-
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "left", "right"]}>
553+
<View className="flex-1 bg-fair-dark">
553554
<ScrollView
554555
className="flex-1"
555556
contentContainerClassName="px-4 pt-4 pb-8"
557+
contentContainerStyle={{ paddingTop: insets.top }}
556558
>
557559
{/* Wallets */}
558560
<SettingsSection title="Wallets">
@@ -732,6 +734,6 @@ export default function SettingsScreen() {
732734
onDismiss={handleRecoveryDismiss}
733735
/>
734736
</ScrollView>
735-
</SafeAreaView>
737+
</View>
736738
);
737739
}

app/coin-control.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
Pressable,
1313
Alert,
1414
} from "react-native";
15-
import { SafeAreaView } from "react-native-safe-area-context";
15+
import { useSafeAreaInsets } from "react-native-safe-area-context";
1616
import { useRouter } from "expo-router";
1717
import { useWalletStore, getDatabase } from "../src/wallet/wallet-store";
1818
import { Button } from "../src/ui/components/Button";
@@ -115,6 +115,7 @@ function UTXORow({ utxo, selected, onToggle }: UTXORowProps) {
115115
// ---------------------------------------------------------------------------
116116

117117
export default function CoinControlScreen() {
118+
const insets = useSafeAreaInsets();
118119
const router = useRouter();
119120
const chainHeight = useWalletStore((s) => s.chainHeight);
120121
const existingSelection = useWalletStore((s) => s.selectedUTXOs);
@@ -210,14 +211,14 @@ export default function CoinControlScreen() {
210211
}, [utxos]);
211212

212213
return (
213-
<SafeAreaView
214+
<View
214215
className="flex-1 bg-fair-dark"
215-
edges={["top", "bottom", "left", "right"]}
216216
onLayout={handleLayout}
217217
>
218218
<ScrollView
219219
className="flex-1"
220220
contentContainerClassName="pb-8"
221+
contentContainerStyle={{ paddingTop: insets.top }}
221222
>
222223
{/* Header info */}
223224
<View className="px-6 pt-4 pb-2">
@@ -286,6 +287,6 @@ export default function CoinControlScreen() {
286287
disabled={selectedCount === 0}
287288
/>
288289
</View>
289-
</SafeAreaView>
290+
</View>
290291
);
291292
}

app/contacts.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
Alert,
1414
FlatList,
1515
} from "react-native";
16-
import { SafeAreaView } from "react-native-safe-area-context";
16+
import { useSafeAreaInsets } from "react-native-safe-area-context";
1717
import { useLocalSearchParams, useRouter } from "expo-router";
1818
import * as Clipboard from "expo-clipboard";
1919
import { useContactsStore } from "../src/wallet/contacts-store";
@@ -263,6 +263,7 @@ function ContactItem({ contact, onPress, onLongPress }: ContactItemProps) {
263263
// ---------------------------------------------------------------------------
264264

265265
export default function ContactsScreen() {
266+
const insets = useSafeAreaInsets();
266267
const router = useRouter();
267268
const params = useLocalSearchParams<{ mode?: string }>();
268269
const isPickMode = params.mode === "pick";
@@ -410,9 +411,9 @@ export default function ContactsScreen() {
410411
const keyExtractor = useCallback((item: ContactRow) => item.id, []);
411412

412413
return (
413-
<SafeAreaView
414+
<View
414415
className="flex-1 bg-fair-dark"
415-
edges={["top", "left", "right", "bottom"]}
416+
style={{ paddingTop: insets.top }}
416417
onLayout={handleLayout}
417418
>
418419
{/* Header */}
@@ -470,6 +471,6 @@ export default function ContactsScreen() {
470471
onSave={handleFormSave}
471472
onClose={handleFormClose}
472473
/>
473-
</SafeAreaView>
474+
</View>
474475
);
475476
}

app/export-key.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
ActivityIndicator,
1717
Modal,
1818
} from "react-native";
19-
import { SafeAreaView } from "react-native-safe-area-context";
19+
import { useSafeAreaInsets } from "react-native-safe-area-context";
2020
import * as Clipboard from "expo-clipboard";
2121
import { useWalletStore } from "../src/wallet/wallet-store";
2222
import { verifyPin } from "../src/storage/secure-store";
@@ -38,6 +38,7 @@ type ExportStep = "pin" | "select" | "passphrase" | "result";
3838
// ---------------------------------------------------------------------------
3939

4040
export default function ExportKeyScreen() {
41+
const insets = useSafeAreaInsets();
4142
const addresses = useWalletStore((s) => s.addresses);
4243
const network = useWalletStore((s) => s.network);
4344

@@ -189,7 +190,7 @@ export default function ExportKeyScreen() {
189190

190191
if (step === "pin") {
191192
return (
192-
<SafeAreaView className="flex-1 bg-fair-dark">
193+
<View className="flex-1 bg-fair-dark" style={{ paddingTop: insets.top }}>
193194
<View className="flex-1 items-center justify-center px-8">
194195
<Text className="text-white text-xl font-bold mb-2">Verify PIN</Text>
195196
<Text className="text-fair-muted text-sm mb-6 text-center">
@@ -259,16 +260,17 @@ export default function ExportKeyScreen() {
259260
))}
260261
</View>
261262
</View>
262-
</SafeAreaView>
263+
</View>
263264
);
264265
}
265266

266267
if (step === "select") {
267268
return (
268-
<SafeAreaView className="flex-1 bg-fair-dark">
269+
<View className="flex-1 bg-fair-dark">
269270
<ScrollView
270271
className="flex-1"
271272
contentContainerClassName="px-6 pt-6 pb-8"
273+
contentContainerStyle={{ paddingTop: insets.top }}
272274
>
273275
<Text className="text-white text-xl font-bold mb-2 text-center">
274276
Select Address
@@ -304,16 +306,17 @@ export default function ExportKeyScreen() {
304306
</View>
305307
)}
306308
</ScrollView>
307-
</SafeAreaView>
309+
</View>
308310
);
309311
}
310312

311313
if (step === "passphrase") {
312314
return (
313-
<SafeAreaView className="flex-1 bg-fair-dark">
315+
<View className="flex-1 bg-fair-dark">
314316
<ScrollView
315317
className="flex-1"
316318
contentContainerClassName="px-6 pt-6 pb-8"
319+
contentContainerStyle={{ paddingTop: insets.top }}
317320
keyboardShouldPersistTaps="handled"
318321
>
319322
<Text className="text-white text-xl font-bold mb-2 text-center">
@@ -366,16 +369,17 @@ export default function ExportKeyScreen() {
366369
loading={encrypting}
367370
/>
368371
</ScrollView>
369-
</SafeAreaView>
372+
</View>
370373
);
371374
}
372375

373376
// Result step
374377
return (
375-
<SafeAreaView className="flex-1 bg-fair-dark">
378+
<View className="flex-1 bg-fair-dark">
376379
<ScrollView
377380
className="flex-1"
378381
contentContainerClassName="px-6 pt-6 pb-8"
382+
contentContainerStyle={{ paddingTop: insets.top }}
379383
>
380384
<Text className="text-white text-xl font-bold mb-2 text-center">
381385
Encrypted Key
@@ -415,6 +419,6 @@ export default function ExportKeyScreen() {
415419
</Text>
416420
</View>
417421
</ScrollView>
418-
</SafeAreaView>
422+
</View>
419423
);
420424
}

app/masternode.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
Modal,
1515
TextInput,
1616
} from "react-native";
17-
import { SafeAreaView } from "react-native-safe-area-context";
17+
import { useSafeAreaInsets } from "react-native-safe-area-context";
1818
import { useFocusEffect } from "expo-router";
1919
import { useWalletStore } from "../src/wallet/wallet-store";
2020
import type { MasternodeUTXO } from "../src/wallet/wallet-store";
@@ -53,6 +53,7 @@ function parseIpPort(input: string): { ip: string; port: number } | null {
5353
}
5454

5555
export default function MasternodeScreen() {
56+
const insets = useSafeAreaInsets();
5657
const masternodeUTXOs = useWalletStore((s) => s.masternodeUTXOs);
5758
const refreshMasternodeUTXOs = useWalletStore((s) => s.refreshMasternodeUTXOs);
5859
const [isBroadcasting, setIsBroadcasting] = useState(false);
@@ -143,10 +144,11 @@ export default function MasternodeScreen() {
143144
}, [ipPortInput, firstEligible]);
144145

145146
return (
146-
<SafeAreaView className="flex-1 bg-fair-dark" edges={["top", "bottom", "left", "right"]}>
147+
<View className="flex-1 bg-fair-dark">
147148
<ScrollView
148149
className="flex-1"
149150
contentContainerClassName="px-6 pt-4 pb-8"
151+
contentContainerStyle={{ paddingTop: insets.top }}
150152
>
151153
{/* Info card */}
152154
<View className="bg-fair-dark-light border border-fair-border rounded-xl p-4 mb-6">
@@ -302,6 +304,6 @@ export default function MasternodeScreen() {
302304
</View>
303305
</View>
304306
</Modal>
305-
</SafeAreaView>
307+
</View>
306308
);
307309
}

0 commit comments

Comments
 (0)