diff --git a/src/components/SignRequestHandler.tsx b/src/components/SignRequestHandler.tsx new file mode 100644 index 0000000..948a59a --- /dev/null +++ b/src/components/SignRequestHandler.tsx @@ -0,0 +1,75 @@ +import React, { useState, useEffect } from 'react'; +import { useNavigation } from '@react-navigation/native'; +import { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useAccounts } from '../context/AccountsContext'; +import { useNetworks } from '../context/NetworksContext'; +import { StackParamsList } from '../types'; +import useGetOrCreateAccounts from '../hooks/useGetOrCreateAccounts'; + +declare global { + interface Window { + receiveSignRequestFromAndroid?: (message: string) => void; + } +} + +export const SignRequestHandler: React.FC = () => { + const navigation = useNavigation>(); + const { accounts, currentIndex } = useAccounts(); + const { selectedNetwork } = useNetworks(); + const [pendingMessage, setPendingMessage] = useState(null); + + useGetOrCreateAccounts(); + + useEffect(() => { + if (pendingMessage && selectedNetwork && accounts && accounts.length > 0) { + navigation.reset({ + index: 0, + routes: [ + { + name: 'SignRequest', + params: { + address: accounts[currentIndex].address, + message: pendingMessage, + requestEvent: null, + path: `/sign/${selectedNetwork.namespace}/${selectedNetwork.chainId}/${accounts[currentIndex].address}/${encodeURIComponent(pendingMessage)}` + } + } + ] + }); + setPendingMessage(null); + } + }, [pendingMessage, selectedNetwork, accounts, currentIndex, navigation]); + + useEffect(() => { + window.receiveSignRequestFromAndroid = (message: string) => { + if (!selectedNetwork || !accounts || accounts.length === 0) { + // Store the message and wait for wallet creation + setPendingMessage(message); + return; + } + + navigation.reset({ + index: 0, + routes: [ + { + name: 'SignRequest', + params: { + address: accounts[currentIndex].address, + message: message, + requestEvent: null, + path: `/sign/${selectedNetwork.namespace}/${selectedNetwork.chainId}/${accounts[currentIndex].address}/${encodeURIComponent(message)}` + } + } + ] + }); + }; + + return () => { + if ('receiveSignRequestFromAndroid' in window) { + window.receiveSignRequestFromAndroid = undefined; + } + }; + }, [navigation, accounts, currentIndex, selectedNetwork]); + + return null; +}; \ No newline at end of file diff --git a/src/hooks/useGetOrCreateAccounts.ts b/src/hooks/useGetOrCreateAccounts.ts index 32a7815..4d16dd8 100644 --- a/src/hooks/useGetOrCreateAccounts.ts +++ b/src/hooks/useGetOrCreateAccounts.ts @@ -1,11 +1,20 @@ import { useEffect } from "react"; - import { createWallet } from "../utils/accounts"; import { sendMessage } from "../utils/misc"; import useAccountsData from "./useAccountsData"; import { useNetworks } from "../context/NetworksContext"; -const useGetOrCreateAccounts = () => { +declare global { + interface Window { + Android?: { + onSignatureComplete?: (signature: string) => void; + onSignatureError?: (error: string) => void; + onSignatureCancelled?: () => void; + }; + } +} + +const useGetOrCreateAccounts = (onWalletCreated?: () => void) => { const { networksData } = useNetworks(); const { getAccountsData } = useAccountsData(); @@ -21,6 +30,8 @@ const useGetOrCreateAccounts = () => { // Re-fetch newly created accounts accountsData = await getAccountsData(event.data.chainId); + + onWalletCreated?.(); } sendMessage( @@ -30,12 +41,33 @@ const useGetOrCreateAccounts = () => { ); }; + const autoCreateAccounts = async () => { + const defaultChainId = networksData[0]?.chainId; + if (!defaultChainId) return; + + let accountsData = await getAccountsData(defaultChainId); + + if (accountsData.length === 0) { + console.log("Auto-creating wallet..."); + await createWallet(networksData); + accountsData = await getAccountsData(defaultChainId); + + onWalletCreated?.(); + } + }; + window.addEventListener('message', handleCreateAccounts); + const isAndroidWebView = !!(window.Android); + + if (isAndroidWebView) { + autoCreateAccounts(); + } + return () => { window.removeEventListener('message', handleCreateAccounts); }; - }, [networksData, getAccountsData]); + }, [networksData, getAccountsData, onWalletCreated]); }; -export default useGetOrCreateAccounts; +export default useGetOrCreateAccounts; \ No newline at end of file diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index ca4ce78..30f2af0 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -18,6 +18,8 @@ import { useNetworks } from "../context/NetworksContext"; import ImportWalletDialog from "../components/ImportWalletDialog"; import { MnemonicDialog } from "../components/MnemonicDialog"; import { Container } from "../components/Container"; +import { SignRequestHandler } from '../components/SignRequestHandler'; +import useGetOrCreateAccounts from '../hooks/useGetOrCreateAccounts'; import { IS_IMPORT_WALLET_ENABLED } from "../utils/constants"; const HomeScreen = () => { @@ -64,8 +66,34 @@ const HomeScreen = () => { setPhrase(mnemonic); setSelectedNetwork(networksData[0]); } + setIsWalletCreating(false); }; + const handleWalletCreated = useCallback(() => { + setIsWalletCreated(true); + fetchAccounts(); + }, [fetchAccounts]); + + useGetOrCreateAccounts(handleWalletCreated); + + useEffect(() => { + fetchAccounts(); + }, [networksData, setAccounts, selectedNetwork, fetchAccounts]); + + useEffect(() => { + const initializeWallet = async () => { + if (!isWalletCreated && networksData.length > 0) { + const mnemonic = await createWallet(networksData); + if (mnemonic) { + await fetchAccounts(); + setSelectedNetwork(networksData[0]); + } + } + }; + + initializeWallet(); + }, [networksData, isWalletCreated, fetchAccounts, setSelectedNetwork]); + const importWalletHandler = async (recoveryPhrase: string) => { try { const mnemonic = await createWallet(networksData, recoveryPhrase); @@ -114,10 +142,6 @@ const HomeScreen = () => { setCurrentIndex(0); }; - useEffect(() => { - fetchAccounts(); - }, [networksData, setAccounts, selectedNetwork, fetchAccounts]); - return ( @@ -161,6 +185,7 @@ const HomeScreen = () => { )} )} + setImportWalletDialog(false)} diff --git a/src/types.ts b/src/types.ts index 95dcb7d..a5b8dd0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,6 +10,7 @@ export type StackParamsList = { selectedNamespace: string; selectedChainId: string; accountInfo: Account; + prefillMessage?: string; }; SignRequest: { namespace: string;