From b395e1b782f2c9b3a034a41f33987491b6874e29 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 4 May 2024 19:38:39 -0400 Subject: [PATCH] FIX: TX details screen would hang when loading large data --- blue_modules/storage-context.tsx | 28 ++++--- screen/transactions/details.js | 126 ++++++++++++++++--------------- 2 files changed, 80 insertions(+), 74 deletions(-) diff --git a/blue_modules/storage-context.tsx b/blue_modules/storage-context.tsx index d8d886d75..defe30506 100644 --- a/blue_modules/storage-context.tsx +++ b/blue_modules/storage-context.tsx @@ -8,6 +8,7 @@ import loc from '../loc'; import * as BlueElectrum from './BlueElectrum'; import triggerHapticFeedback, { HapticFeedbackTypes } from './hapticFeedback'; import A from '../blue_modules/analytics'; +import { InteractionManager } from 'react-native'; const BlueApp = BlueAppClass.getInstance(); @@ -71,30 +72,27 @@ export const BlueStorageProvider = ({ children }: { children: React.ReactNode }) const [reloadTransactionsMenuActionFunction, setReloadTransactionsMenuActionFunction] = useState<() => void>(() => {}); useEffect(() => { - BlueElectrum.isDisabled().then(setIsElectrumDisabled); - }, []); + setWallets(BlueApp.getWallets()); - useEffect(() => { + BlueElectrum.isDisabled().then(setIsElectrumDisabled); if (walletsInitialized) { BlueElectrum.connectMain(); } }, [walletsInitialized]); const saveToDisk = async (force: boolean = false) => { - if (BlueApp.getWallets().length === 0 && !force) { - console.log('not saving empty wallets array'); - return; - } - BlueApp.tx_metadata = txMetadata; - await BlueApp.saveToDisk(); - setWallets([...BlueApp.getWallets()]); - txMetadata = BlueApp.tx_metadata; + InteractionManager.runAfterInteractions(async () => { + if (BlueApp.getWallets().length === 0 && !force) { + console.log('not saving empty wallets array'); + return; + } + BlueApp.tx_metadata = txMetadata; + await BlueApp.saveToDisk(); + setWallets([...BlueApp.getWallets()]); + txMetadata = BlueApp.tx_metadata; + }); }; - useEffect(() => { - setWallets(BlueApp.getWallets()); - }, []); - const resetWallets = () => { setWallets(BlueApp.getWallets()); }; diff --git a/screen/transactions/details.js b/screen/transactions/details.js index 97b1e2b0c..247a7d16c 100644 --- a/screen/transactions/details.js +++ b/screen/transactions/details.js @@ -1,6 +1,6 @@ -import React, { useContext, useEffect, useLayoutEffect, useState } from 'react'; -import { View, ScrollView, TouchableOpacity, Text, TextInput, Linking, StyleSheet, Keyboard } from 'react-native'; -import { useNavigation, useRoute } from '@react-navigation/native'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { View, ScrollView, TouchableOpacity, Text, TextInput, Linking, StyleSheet, Keyboard, InteractionManager } from 'react-native'; +import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native'; import Clipboard from '@react-native-clipboard/clipboard'; import dayjs from 'dayjs'; import { BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents'; @@ -59,68 +59,76 @@ const TransactionsDetails = () => { }, }); - useLayoutEffect(() => { - setOptions({ - // eslint-disable-next-line react/no-unstable-nested-components - headerRight: () => ( - - {loc.wallets.details_save} - - ), - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [colors, isLoading, memo]); - - useEffect(() => { - let foundTx = {}; - let newFrom = []; - let newTo = []; - for (const transaction of getTransactions(null, Infinity, true)) { - if (transaction.hash === hash) { - foundTx = transaction; - for (const input of foundTx.inputs) { - newFrom = newFrom.concat(input.addresses); - } - for (const output of foundTx.outputs) { - if (output.addresses) newTo = newTo.concat(output.addresses); - if (output.scriptPubKey && output.scriptPubKey.addresses) newTo = newTo.concat(output.scriptPubKey.addresses); - } - } - } - - for (const w of wallets) { - for (const t of w.getTransactions()) { - if (t.hash === hash) { - console.log('tx', hash, 'belongs to', w.getLabel()); - } - } - } - if (txMetadata[foundTx.hash]) { - if (txMetadata[foundTx.hash].memo) { - setMemo(txMetadata[foundTx.hash].memo); - } - } - - setTX(foundTx); - setFrom(newFrom); - setTo(newTo); - setIsLoading(false); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [hash, wallets]); - - const handleOnSaveButtonTapped = () => { + const handleOnSaveButtonTapped = useCallback(() => { Keyboard.dismiss(); txMetadata[tx.hash] = { memo }; saveToDisk().then(_success => { triggerHapticFeedback(HapticFeedbackTypes.Success); presentAlert({ message: loc.transactions.transaction_note_saved }); }); - }; + }, [tx, memo, saveToDisk, txMetadata]); + + const HeaderRightButton = useMemo(() => { + return ( + + {loc.wallets.details_save} + + ); + }, [isLoading, stylesHooks.save, stylesHooks.saveText, handleOnSaveButtonTapped]); + + useEffect(() => { + // This effect only handles changes in `colors` + setOptions({ headerRight: () => HeaderRightButton }); + }, [colors, HeaderRightButton, setOptions]); + + useFocusEffect( + useCallback(() => { + const task = InteractionManager.runAfterInteractions(() => { + let foundTx = {}; + let newFrom = []; + let newTo = []; + for (const transaction of getTransactions(null, Infinity, true)) { + if (transaction.hash === hash) { + foundTx = transaction; + for (const input of foundTx.inputs) { + newFrom = newFrom.concat(input.addresses); + } + for (const output of foundTx.outputs) { + if (output.addresses) newTo = newTo.concat(output.addresses); + if (output.scriptPubKey && output.scriptPubKey.addresses) newTo = newTo.concat(output.scriptPubKey.addresses); + } + } + } + + for (const w of wallets) { + for (const t of w.getTransactions()) { + if (t.hash === hash) { + console.log('tx', hash, 'belongs to', w.getLabel()); + } + } + } + if (txMetadata[foundTx.hash]) { + if (txMetadata[foundTx.hash].memo) { + setMemo(txMetadata[foundTx.hash].memo); + } + } + + setTX(foundTx); + setFrom(newFrom); + setTo(newTo); + setIsLoading(false); + }); + return () => { + task.cancel(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [hash, wallets]), + ); const handleOnOpenTransactionOnBlockExplorerTapped = () => { const url = `https://mempool.space/tx/${tx.hash}`;