Skip to content
Merged
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
211 changes: 150 additions & 61 deletions packages/mobile-app/app/(drawer)/app-settings/network/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Text,
View,
ActivityIndicator,
TouchableOpacity,
} from "react-native";
import { useState } from "react";
import { useFacade } from "@/data/facades";
Expand All @@ -15,6 +16,7 @@ import { AccountFormat } from "@ironfish/sdk";
export default function MenuNetwork() {
const [modalVisible, setModalVisible] = useState(false);
const [isChangingNetwork, setIsChangingNetwork] = useState(false);
const [pendingNetwork, setPendingNetwork] = useState<Network | null>(null);

const facade = useFacade();
const setAppSetting = facade.setAppSetting.useMutation();
Expand All @@ -25,8 +27,13 @@ export default function MenuNetwork() {

const currentNetwork =
networkSetting.data?.[SettingsKey.Network] ?? Network.MAINNET;
const targetNetwork =
currentNetwork === Network.MAINNET ? Network.TESTNET : Network.MAINNET;

const handleNetworkPress = (network: Network) => {
if (network !== currentNetwork) {
setPendingNetwork(network);
setModalVisible(true);
}
};

const handleNetworkChange = async (network: Network) => {
setIsChangingNetwork(true);
Expand Down Expand Up @@ -58,6 +65,7 @@ export default function MenuNetwork() {
} finally {
setIsChangingNetwork(false);
setModalVisible(false);
setPendingNetwork(null);
}
};

Expand All @@ -72,59 +80,85 @@ export default function MenuNetwork() {

return (
<View style={styles.container}>
<Modal animationType="slide" visible={modalVisible}>
<View style={styles.container}>
{isChangingNetwork ? (
<>
<ActivityIndicator size="large" />
<Text style={styles.loadingText}>
Changing network and re-importing accounts...
</Text>
</>
) : (
<>
<Text>Switch to {targetNetwork}?</Text>
<Text>
Switching networks will upload your accounts to the{" "}
{targetNetwork} server. It may take a few minutes for your
accounts to sync.
</Text>
<Button
title="Yes, Change Network"
onPress={() => handleNetworkChange(targetNetwork)}
/>
<Button
title="I changed my mind"
onPress={() => setModalVisible(false)}
/>
</>
)}
<Modal animationType="fade" visible={modalVisible} transparent>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
{isChangingNetwork ? (
<>
<ActivityIndicator size="large" color="#007AFF" />
<Text style={styles.modalText}>
Changing network and re-importing accounts...
</Text>
</>
) : (
<>
<Text style={styles.modalTitle}>
Switch to {pendingNetwork}?
</Text>
<Text style={styles.modalText}>
Switching networks will upload your accounts to the{" "}
{pendingNetwork} server. It may take a few minutes for your
accounts to sync.
</Text>
<View style={styles.modalButtons}>
<Button
title="Yes, Change Network"
onPress={() => handleNetworkChange(pendingNetwork!)}
color="#007AFF"
/>
<Button
title="Cancel"
onPress={() => {
setModalVisible(false);
setPendingNetwork(null);
}}
color="#666"
/>
</View>
</>
)}
</View>
</View>
</Modal>
<View style={styles.networkOption}>
<View style={styles.networkInfo}>
<Text style={styles.networkTitle}>Mainnet</Text>
<Text style={styles.networkDescription}>
The live blockchain network where real transactions with value
occur.
</Text>
{currentNetwork === Network.MAINNET && (
<Text style={styles.selectedText}>(Selected)</Text>
)}
</View>
</View>
<View style={styles.networkOption}>
<View style={styles.networkInfo}>
<Text style={styles.networkTitle}>Testnet</Text>
<Text style={styles.networkDescription}>
A separate environment for testing without real asset risks.
</Text>
{currentNetwork === Network.TESTNET && (
<Text style={styles.selectedText}>(Selected)</Text>
)}
</View>

<View style={styles.content}>
<TouchableOpacity
style={[
styles.networkOption,
currentNetwork === Network.MAINNET && styles.networkOptionSelected,
]}
onPress={() => handleNetworkPress(Network.MAINNET)}
>
<View style={styles.networkInfo}>
<Text style={styles.networkTitle}>Mainnet</Text>
<Text style={styles.networkDescription}>
The live blockchain network where real transactions with value
occur.
</Text>
{currentNetwork === Network.MAINNET && (
<Text style={styles.selectedText}>(Selected)</Text>
)}
</View>
</TouchableOpacity>

<TouchableOpacity
style={[
styles.networkOption,
currentNetwork === Network.TESTNET && styles.networkOptionSelected,
]}
onPress={() => handleNetworkPress(Network.TESTNET)}
>
<View style={styles.networkInfo}>
<Text style={styles.networkTitle}>Testnet</Text>
<Text style={styles.networkDescription}>
A separate environment for testing without real asset risks.
</Text>
{currentNetwork === Network.TESTNET && (
<Text style={styles.selectedText}>(Selected)</Text>
)}
</View>
</TouchableOpacity>
</View>
<Button title="Change Network" onPress={() => setModalVisible(true)} />
</View>
);
}
Expand All @@ -133,35 +167,90 @@ const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
networkOption: {
width: "100%",
content: {
flex: 1,
padding: 16,
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
networkOption: {
backgroundColor: "#F8F9FC",
borderRadius: 12,
marginBottom: 16,
padding: 20,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 3,
elevation: 3,
borderWidth: 2,
borderColor: "transparent",
},
networkOptionSelected: {
borderColor: "#007AFF",
backgroundColor: "#F0F7FF",
},
networkInfo: {
alignItems: "center",
},
networkTitle: {
fontSize: 18,
fontWeight: "bold",
fontSize: 20,
fontWeight: "600",
marginBottom: 8,
color: "#000",
},
networkDescription: {
textAlign: "center",
color: "#666",
marginBottom: 8,
lineHeight: 20,
},
selectedText: {
color: "#007AFF",
fontWeight: "500",
fontWeight: "600",
marginTop: 4,
},
loadingText: {
marginTop: 16,
fontSize: 16,
color: "#666",
textAlign: "center",
},
buttonContainer: {
padding: 16,
paddingBottom: 32,
},
modalOverlay: {
flex: 1,
backgroundColor: "rgba(0, 0, 0, 0.5)",
justifyContent: "center",
alignItems: "center",
},
modalContent: {
backgroundColor: "#fff",
borderRadius: 12,
padding: 24,
width: "90%",
maxWidth: 400,
alignItems: "center",
},
modalTitle: {
fontSize: 20,
fontWeight: "600",
marginBottom: 16,
textAlign: "center",
},
modalText: {
fontSize: 16,
color: "#666",
textAlign: "center",
marginBottom: 24,
lineHeight: 22,
},
modalButtons: {
width: "100%",
gap: 12,
},
});
Loading