import { RouteProp, useFocusEffect, useRoute } from '@react-navigation/native'; import React, { useCallback, useMemo, useReducer, useRef } from 'react'; import { ActivityIndicator, InteractionManager, ScrollView, StyleSheet, View } from 'react-native'; import { BlueSpacing20, BlueText } from '../../BlueComponents'; import { TWallet } from '../../class/wallets/types'; import { DynamicQRCode } from '../../components/DynamicQRCode'; import SaveFileButton from '../../components/SaveFileButton'; import { SquareButton } from '../../components/SquareButton'; import { useTheme } from '../../components/themes'; import usePrivacy from '../../hooks/usePrivacy'; import loc from '../../loc'; import { useStorage } from '../../hooks/context/useStorage'; type RootStackParamList = { ExportMultisigCoordinationSetup: { walletID: string; }; }; const enum ActionType { SET_LOADING = 'SET_LOADING', SET_SHARE_BUTTON_TAPPED = 'SET_SHARE_BUTTON_TAPPED', SET_ERROR = 'SET_ERROR', SET_QR_CODE_CONTENTS = 'SET_QR_CODE_CONTENTS', } type State = { isLoading: boolean; isShareButtonTapped: boolean; qrCodeContents?: string; error: string | null; }; type Action = | { type: ActionType.SET_LOADING; isLoading: boolean } | { type: ActionType.SET_SHARE_BUTTON_TAPPED; isShareButtonTapped: boolean } | { type: ActionType.SET_ERROR; error: string | null } | { type: ActionType.SET_QR_CODE_CONTENTS; qrCodeContents: string }; function reducer(state: State, action: Action): State { switch (action.type) { case ActionType.SET_LOADING: return { ...state, isLoading: action.isLoading }; case ActionType.SET_SHARE_BUTTON_TAPPED: return { ...state, isShareButtonTapped: action.isShareButtonTapped }; case ActionType.SET_ERROR: return { ...state, error: action.error, isLoading: false }; case ActionType.SET_QR_CODE_CONTENTS: return { ...state, qrCodeContents: action.qrCodeContents, isLoading: false }; default: return state; } } const initialState: State = { isLoading: true, isShareButtonTapped: false, qrCodeContents: undefined, error: null, }; const ExportMultisigCoordinationSetup: React.FC = () => { const [state, dispatch] = useReducer(reducer, initialState); const { isLoading, isShareButtonTapped, qrCodeContents } = state; const { params } = useRoute>(); const walletID = params.walletID; const { wallets } = useStorage(); const wallet: TWallet | undefined = wallets.find(w => w.getID() === walletID); const dynamicQRCode = useRef(); const { colors } = useTheme(); const { enableBlur, disableBlur } = usePrivacy(); const stylesHook = StyleSheet.create({ scrollViewContent: { backgroundColor: colors.elevated, }, type: { color: colors.foregroundColor }, secret: { color: colors.foregroundColor }, exportButton: { backgroundColor: colors.buttonDisabledBackgroundColor, }, }); const label = useMemo(() => wallet?.getLabel(), [wallet]); const xpub = useMemo(() => wallet?.getXpub(), [wallet]); const setIsShareButtonTapped = (value: boolean) => { dispatch({ type: ActionType.SET_SHARE_BUTTON_TAPPED, isShareButtonTapped: value }); }; useFocusEffect( useCallback(() => { dispatch({ type: ActionType.SET_LOADING, isLoading: true }); const task = InteractionManager.runAfterInteractions(async () => { enableBlur(); if (wallet) { try { if (typeof xpub === 'string') { const value = Buffer.from(xpub, 'ascii').toString('hex'); dispatch({ type: ActionType.SET_QR_CODE_CONTENTS, qrCodeContents: value }); } else { throw new Error('Expected getXpub() to return a string.'); } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred'; dispatch({ type: ActionType.SET_ERROR, error: errorMessage }); } } else { dispatch({ type: ActionType.SET_ERROR, error: 'Wallet not found' }); } }); return () => { task.cancel(); disableBlur(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [walletID]), ); const exportTxtFileBeforeOnPress = async () => { setIsShareButtonTapped(true); dynamicQRCode.current?.stopAutoMove(); }; const exportTxtFileAfterOnPress = () => { setIsShareButtonTapped(false); dynamicQRCode.current?.startAutoMove(); }; const renderView = wallet ? ( <> {wallet.getLabel()} {qrCodeContents && } {isShareButtonTapped ? ( ) : ( label && xpub && ( ) )} {wallet.getXpub()} ) : null; return ( {isLoading ? : renderView} ); }; const styles = StyleSheet.create({ scrollViewContent: { alignItems: 'center', justifyContent: 'center', flexGrow: 1, }, type: { fontSize: 17, fontWeight: '700', }, secret: { alignItems: 'center', paddingHorizontal: 16, fontSize: 16, lineHeight: 24, }, exportButton: { height: 48, borderRadius: 8, flex: 1, justifyContent: 'center', paddingHorizontal: 16, width: '80%', maxWidth: 300, }, }); export default ExportMultisigCoordinationSetup;