From 472f4c214cf8c2f0f71b461b4006d90ef7d70575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Rodriguez=20V=C3=A9lez?= <marcospr@pm.me> Date: Sun, 18 Jul 2021 11:54:43 -0400 Subject: [PATCH] REF: Remove error-prone random placeholder scroll calculation --- BlueComponents.js | 3 +- blue_modules/storage-context.js | 6 +- class/wallet-import.js | 36 +++++----- components/WalletsCarousel.js | 112 +++++++++++++++++--------------- screen/wallets/drawerList.js | 79 ++++++---------------- screen/wallets/import.js | 36 ++++++++-- screen/wallets/list.js | 95 +++++++++------------------ 7 files changed, 158 insertions(+), 209 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index 0c816dbe1..43ee8ce59 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -831,6 +831,7 @@ export const BlueHeaderDefaultSub = props => { export const BlueHeaderDefaultMain = props => { const { colors } = useTheme(); const { isDrawerList } = props; + const { isImportingWallet } = useContext(BlueStorageContext); return ( <Header leftComponent={{ @@ -854,7 +855,7 @@ export const BlueHeaderDefaultMain = props => { bottomDivider={false} topDivider={false} backgroundColor={isDrawerList ? colors.elevated : colors.background} - rightComponent={<BluePlusIcon onPress={props.onNewWalletPress} Component={TouchableOpacity} />} + rightComponent={isImportingWallet ? undefined : <BluePlusIcon onPress={props.onNewWalletPress} Component={TouchableOpacity} />} /> ); }; diff --git a/blue_modules/storage-context.js b/blue_modules/storage-context.js index 7f42aa058..8c3be1f23 100644 --- a/blue_modules/storage-context.js +++ b/blue_modules/storage-context.js @@ -14,7 +14,7 @@ export const WalletTransactionsStatus = { NONE: false, ALL: true }; export const BlueStorageContext = createContext(); export const BlueStorageProvider = ({ children }) => { const [wallets, setWallets] = useState([]); - const [pendingWallets, setPendingWallets] = useState([]); + const [isImportingWallet, setIsImportingWallet] = useState(false); const [selectedWallet, setSelectedWallet] = useState(''); const [walletTransactionUpdateStatus, setWalletTransactionUpdateStatus] = useState(WalletTransactionsStatus.NONE); const [walletsInitialized, setWalletsInitialized] = useState(false); @@ -186,8 +186,8 @@ export const BlueStorageProvider = ({ children }) => { value={{ wallets, setWalletsWithNewOrder, - pendingWallets, - setPendingWallets, + isImportingWallet, + setIsImportingWallet, txMetadata, saveToDisk, getTransactions, diff --git a/class/wallet-import.js b/class/wallet-import.js index 10f3011e0..06c440aa0 100644 --- a/class/wallet-import.js +++ b/class/wallet-import.js @@ -8,13 +8,13 @@ import { HDLegacyP2PKHWallet, HDSegwitBech32Wallet, LightningCustodianWallet, - PlaceholderWallet, SegwitBech32Wallet, HDLegacyElectrumSeedP2PKHWallet, HDSegwitElectrumSeedP2WPKHWallet, HDAezeedWallet, MultisigHDWallet, SLIP39LegacyP2PKHWallet, + PlaceholderWallet, SLIP39SegwitP2SHWallet, SLIP39SegwitBech32Wallet, } from '.'; @@ -30,7 +30,7 @@ const wif = require('wif'); const prompt = require('../blue_modules/prompt'); function WalletImport() { - const { wallets, pendingWallets, setPendingWallets, saveToDisk, addWallet } = useContext(BlueStorageContext); + const { wallets, saveToDisk, addWallet, setIsImportingWallet } = useContext(BlueStorageContext); /** * @@ -55,15 +55,21 @@ function WalletImport() { Notifications.majorTomToGroundControl(w.getAllExternalAddresses(), [], []); }; - WalletImport.removePlaceholderWallet = () => { - setPendingWallets([]); + WalletImport.isWalletImported = w => { + const wallet = wallets.some(wallet => wallet.getSecret() === w.secret || wallet.getID() === w.getID()); + return !!wallet; }; - WalletImport.isWalletImported = w => { - const wallet = wallets.some( - wallet => (wallet.getSecret() === w.secret || wallet.getID() === w.getID()) && wallet.type !== PlaceholderWallet.type, - ); - return !!wallet; + WalletImport.removePlaceholderWallet = ()=> { + setIsImportingWallet(false) + } + + + WalletImport.addPlaceholderWallet = (importText, isFailure = false) => { + const placeholderWallet = new PlaceholderWallet(); + placeholderWallet.setSecret(importText); + placeholderWallet.setIsFailure(isFailure); + setIsImportingWallet(placeholderWallet); }; WalletImport.presentWalletAlreadyExistsAlert = () => { @@ -71,18 +77,6 @@ function WalletImport() { alert('This wallet has been previously imported.'); }; - WalletImport.addPlaceholderWallet = (importText, isFailure = false) => { - const wallet = new PlaceholderWallet(); - wallet.setSecret(importText); - wallet.setIsFailure(isFailure); - setPendingWallets([...pendingWallets, wallet]); - return wallet; - }; - - WalletImport.isCurrentlyImportingWallet = () => { - return wallets.some(wallet => wallet.type === PlaceholderWallet.type); - }; - /** * * @param importText diff --git a/components/WalletsCarousel.js b/components/WalletsCarousel.js index f71278174..5b49cd4be 100644 --- a/components/WalletsCarousel.js +++ b/components/WalletsCarousel.js @@ -52,6 +52,43 @@ const nStyles = StyleSheet.create({ }, }); +const PlaceholderWalletCarouselItem = props => { + const { colors } = useTheme(); + + const { isImportingWallet } = useContext(BlueStorageContext); + + return ( + <TouchableWithoutFeedback + onPressIn={() => { + if (isImportingWallet && isImportingWallet.getIsFailure()) { + props.onPressedIn(); + } else { + props.onPressedOut(); + } + }} + onPressOut={isImportingWallet && isImportingWallet.getIsFailure() ? props.onPressedOut : null} + onPress={isImportingWallet && isImportingWallet.getIsFailure() ? props.onPress : null} + > + <LinearGradient shadowColor={colors.shadowColor} colors={WalletGradient.gradientsFor(PlaceholderWallet.type)} style={iStyles.grad}> + <Image source={I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png')} style={iStyles.image} /> + <Text style={iStyles.br} /> + <Text numberOfLines={1} style={[iStyles.label, { color: colors.inverseForegroundColor }]}> + {isImportingWallet.getIsFailure() ? loc.wallets.import_placeholder_fail : loc.wallets.import_placeholder_inprogress} + </Text> + {isImportingWallet.getIsFailure() ? ( + <Text testID="ImportError" numberOfLines={0} style={[iStyles.importError, { color: colors.inverseForegroundColor }]}> + {loc.wallets.list_import_error} + </Text> + ) : ( + <ActivityIndicator style={iStyles.activity} /> + )} + </LinearGradient> + </TouchableWithoutFeedback> + ); +}; + +PlaceholderWalletCarouselItem.propTypes = { onPress: PropTypes.func, onPressedOut: PropTypes.func, onPressedIn: PropTypes.func }; + const NewWalletPanel = ({ onPress }) => { const { colors } = useTheme(); const { width } = useWindowDimensions(); @@ -149,7 +186,7 @@ const iStyles = StyleSheet.create({ const WalletCarouselItem = ({ item, index, onPress, handleLongPress, isSelectedWallet }) => { const scaleValue = new Animated.Value(1.0); const { colors } = useTheme(); - const { walletTransactionUpdateStatus } = useContext(BlueStorageContext); + const { walletTransactionUpdateStatus, isImportingWallet } = useContext(BlueStorageContext); const { width } = useWindowDimensions(); const itemWidth = width * 0.82 > 375 ? 375 : width * 0.82; const isLargeScreen = Platform.OS === 'android' ? isTablet() : width >= Dimensions.get('screen').width / 2 && (isTablet() || isDesktop); @@ -168,7 +205,16 @@ const WalletCarouselItem = ({ item, index, onPress, handleLongPress, isSelectedW }; if (!item) - return ( + return isImportingWallet ? ( + <Animated.View + style={[isLargeScreen ? iStyles.rootLargeDevice : { ...iStyles.root, width: itemWidth }, { transform: [{ scale: scaleValue }] }]} + shadowOpacity={25 / 100} + shadowOffset={{ width: 0, height: 3 }} + shadowRadius={8} + > + <PlaceholderWalletCarouselItem onPress={onPress} index={index} onPressedIn={onPressedIn} onPressedOut={onPressedOut} /> + </Animated.View> + ) : ( <NewWalletPanel onPress={() => { onPressedOut(); @@ -177,47 +223,6 @@ const WalletCarouselItem = ({ item, index, onPress, handleLongPress, isSelectedW /> ); - if (item.type === PlaceholderWallet.type) { - return ( - <Animated.View - style={[isLargeScreen ? iStyles.rootLargeDevice : { ...iStyles.root, width: itemWidth }, { transform: [{ scale: scaleValue }] }]} - shadowOpacity={40 / 100} - shadowOffset={{ width: 0, height: 0 }} - shadowRadius={5} - > - <TouchableWithoutFeedback - onPressIn={item.getIsFailure() ? onPressedIn : null} - onPressOut={item.getIsFailure() ? onPressedOut : null} - onPress={() => { - if (item.getIsFailure()) { - onPressedOut(); - onPress(index); - onPressedOut(); - } - }} - > - <LinearGradient shadowColor={colors.shadowColor} colors={WalletGradient.gradientsFor(item.type)} style={iStyles.grad}> - <Image - source={I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png')} - style={iStyles.image} - /> - <Text style={iStyles.br} /> - <Text numberOfLines={1} style={[iStyles.label, { color: colors.inverseForegroundColor }]}> - {item.getIsFailure() ? loc.wallets.import_placeholder_fail : loc.wallets.import_placeholder_inprogress} - </Text> - {item.getIsFailure() ? ( - <Text testID="ImportError" numberOfLines={0} style={[iStyles.importError, { color: colors.inverseForegroundColor }]}> - {loc.wallets.list_import_error} - </Text> - ) : ( - <ActivityIndicator style={iStyles.activity} /> - )} - </LinearGradient> - </TouchableWithoutFeedback> - </Animated.View> - ); - } - const opacity = isSelectedWallet === false ? 0.5 : 1.0; let image; switch (item.type) { @@ -318,11 +323,11 @@ const cStyles = StyleSheet.create({ }); const WalletsCarousel = forwardRef((props, ref) => { - const { preferredFiatCurrency, language } = useContext(BlueStorageContext); + const { preferredFiatCurrency, language, isImportingWallet } = useContext(BlueStorageContext); const renderItem = useCallback( ({ item, index }) => ( <WalletCarouselItem - isSelectedWallet={props.vertical && props.selectedWallet && item ? props.selectedWallet === item.getID() : undefined} + isSelectedWallet={!props.horizontal && props.selectedWallet && item ? props.selectedWallet === item.getID() : undefined} item={item} index={index} handleLongPress={props.handleLongPress} @@ -330,7 +335,7 @@ const WalletsCarousel = forwardRef((props, ref) => { /> ), // eslint-disable-next-line react-hooks/exhaustive-deps - [props.vertical, props.selectedWallet, props.handleLongPress, props.onPress, preferredFiatCurrency, language], + [props.horizontal, props.selectedWallet, props.handleLongPress, props.onPress, preferredFiatCurrency, language, isImportingWallet], ); const flatListRef = useRef(); const ListHeaderComponent = () => <View style={cStyles.separatorStyle} />; @@ -338,12 +343,12 @@ const WalletsCarousel = forwardRef((props, ref) => { useImperativeHandle(ref, () => ({ scrollToItem: ({ item }) => { setTimeout(() => { - flatListRef?.current?.scrollToItem({ item, viewPosition: 0.3 }); + flatListRef?.current?.scrollToItem({ item, viewOffset: 16 }); }, 300); }, - scrollToIndex: index => { + scrollToIndex: ({ index }) => { setTimeout(() => { - flatListRef?.current?.scrollToIndex({ index, viewPosition: 0.3 }); + flatListRef?.current?.scrollToIndex({ index, viewOffset: 16 }); }, 300); }, })); @@ -351,31 +356,30 @@ const WalletsCarousel = forwardRef((props, ref) => { const { width } = useWindowDimensions(); const sliderHeight = 190; const itemWidth = width * 0.82 > 375 ? 375 : width * 0.82; - const isLargeScreen = Platform.OS === 'android' ? isTablet() : width >= Dimensions.get('screen').width / 2 && (isTablet() || isDesktop); - return ( <FlatList ref={flatListRef} renderItem={renderItem} + extraData={renderItem} keyExtractor={(_, index) => index.toString()} showsVerticalScrollIndicator={false} pagingEnabled disableIntervalMomentum={isHandset} snapToInterval={itemWidth} // Adjust to your content width decelerationRate="fast" - contentContainerStyle={isLargeScreen ? cStyles.contentLargeScreen : cStyles.content} + contentContainerStyle={props.horizontal ? cStyles.content : cStyles.contentLargeScreen} directionalLockEnabled showsHorizontalScrollIndicator={false} initialNumToRender={10} ListHeaderComponent={ListHeaderComponent} - style={props.vertical ? {} : { height: sliderHeight + 9 }} + style={props.horizontal ? { height: sliderHeight + 9 } : {}} {...props} /> ); }); WalletsCarousel.propTypes = { - vertical: PropTypes.bool, + horizontal: PropTypes.bool, selectedWallet: PropTypes.string, onPress: PropTypes.func.isRequired, handleLongPress: PropTypes.func.isRequired, diff --git a/screen/wallets/drawerList.js b/screen/wallets/drawerList.js index 030fcc2bf..24eb202f6 100644 --- a/screen/wallets/drawerList.js +++ b/screen/wallets/drawerList.js @@ -1,5 +1,5 @@ -import React, { useContext, useEffect, useRef, useState } from 'react'; -import { StatusBar, View, StyleSheet, Alert } from 'react-native'; +import React, { useContext, useEffect, useRef } from 'react'; +import { StatusBar, View, StyleSheet } from 'react-native'; import { DrawerContentScrollView } from '@react-navigation/drawer'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import PropTypes from 'prop-types'; @@ -7,8 +7,6 @@ import { useIsFocused, useTheme } from '@react-navigation/native'; import { BlueHeaderDefaultMain, BlueSpacing20 } from '../../BlueComponents'; import WalletsCarousel from '../../components/WalletsCarousel'; -import { PlaceholderWallet } from '../../class'; -import WalletImport from '../../class/wallet-import'; import loc from '../../loc'; import { BlueStorageContext } from '../../blue_modules/storage-context'; import { BlurView } from '@react-native-community/blur'; @@ -16,8 +14,7 @@ import { BlurView } from '@react-native-community/blur'; const DrawerList = props => { console.log('drawerList rendering...'); const walletsCarousel = useRef(); - const { wallets, selectedWallet, pendingWallets, isDrawerListBlurred } = useContext(BlueStorageContext); - const [carouselData, setCarouselData] = useState([]); + const { wallets, selectedWallet, isImportingWallet, isDrawerListBlurred } = useContext(BlueStorageContext); const { colors } = useTheme(); const walletsCount = useRef(wallets.length); const isFocused = useIsFocused(); @@ -27,14 +24,6 @@ const DrawerList = props => { }, }); - useEffect(() => { - const allWallets = wallets.concat(pendingWallets); - setCarouselData(allWallets.concat(false)); - const newCarouselData = allWallets.concat(false); - setCarouselData(newCarouselData); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [wallets, pendingWallets]); - useEffect(() => { if (walletsCount.current < wallets.length) { walletsCarousel.current?.scrollToItem({ item: wallets[walletsCount.current] }); @@ -43,56 +32,29 @@ const DrawerList = props => { }, [wallets]); useEffect(() => { - if (pendingWallets.length > 0) { - walletsCarousel.current?.scrollToItem(carouselData.length - pendingWallets.length); + if (isImportingWallet) { + walletsCarousel.current?.scrollToItem({ item: false }); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [pendingWallets]); + }, [isImportingWallet]); const handleClick = index => { console.log('click', index); - const wallet = carouselData[index]; - if (wallet) { - if (wallet.type === PlaceholderWallet.type) { - Alert.alert( - loc.wallets.add_details, - loc.wallets.list_import_problem, - [ - { - text: loc.wallets.details_delete, - onPress: () => { - WalletImport.removePlaceholderWallet(); - }, - style: 'destructive', - }, - { - text: loc.wallets.list_tryagain, - onPress: () => { - props.navigation.navigate('AddWalletRoot', { screen: 'ImportWallet', params: { label: wallet.getSecret() } }); - WalletImport.removePlaceholderWallet(); - }, - style: 'default', - }, - ], - { cancelable: false }, - ); - } else { - props.navigation.navigate('WalletTransactions', { - walletID: wallet.getID(), - walletType: wallet.type, - key: `WalletTransactions-${wallet.getID()}`, - }); - } - } else { - // if its out of index - this must be last card with incentive to create wallet - if (!carouselData.some(wallet => wallet.type === PlaceholderWallet.type)) { - props.navigation.navigate('Navigation', { screen: 'AddWalletRoot' }); - } + if (index <= wallets.length - 1) { + const wallet = wallets[index]; + const walletID = wallet.getID(); + props.navigation.navigate('WalletTransactions', { + walletID: wallet.getID(), + walletType: wallet.type, + key: `WalletTransactions-${walletID}`, + }); + } else if (index >= wallets.length && !isImportingWallet) { + props.navigation.navigate('Navigation', { screen: 'AddWalletRoot' }); } }; const handleLongPress = () => { - if (carouselData.length > 1 && !carouselData.some(wallet => wallet.type === PlaceholderWallet.type)) { + if (wallets.length > 1 && !isImportingWallet) { props.navigation.navigate('ReorderWallets'); } else { ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); @@ -100,7 +62,7 @@ const DrawerList = props => { }; const onNewWalletPress = () => { - return !carouselData.some(wallet => wallet.type === PlaceholderWallet.type) ? props.navigation.navigate('AddWalletRoot') : null; + return !isImportingWallet ? props.navigation.navigate('AddWalletRoot') : null; }; const ListHeaderComponent = () => { @@ -114,13 +76,12 @@ const DrawerList = props => { const renderWalletsCarousel = ( <WalletsCarousel - data={carouselData} - extraData={carouselData} + data={wallets.concat(false)} + extraData={[wallets, isImportingWallet]} onPress={handleClick} handleLongPress={handleLongPress} ref={walletsCarousel} testID="WalletsList" - vertical selectedWallet={selectedWallet} ListHeaderComponent={ListHeaderComponent} scrollEnabled={isFocused} diff --git a/screen/wallets/import.js b/screen/wallets/import.js index eb8d6a014..4fdd21267 100644 --- a/screen/wallets/import.js +++ b/screen/wallets/import.js @@ -1,6 +1,5 @@ -/* global alert */ -import React, { useEffect, useState } from 'react'; -import { Platform, View, Keyboard, StatusBar, StyleSheet } from 'react-native'; +import React, { useContext, useEffect, useState } from 'react'; +import { Platform, View, Keyboard, StatusBar, StyleSheet, Alert } from 'react-native'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import { useNavigation, useRoute, useTheme } from '@react-navigation/native'; import { @@ -17,11 +16,14 @@ import Privacy from '../../blue_modules/Privacy'; import WalletImport from '../../class/wallet-import'; import loc from '../../loc'; import { isDesktop, isMacCatalina } from '../../blue_modules/environment'; +import { BlueStorageContext } from '../../blue_modules/storage-context'; + const fs = require('../../blue_modules/fs'); const WalletsImport = () => { const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState(false); const route = useRoute(); + const { isImportingWallet } = useContext(BlueStorageContext); const label = (route.params && route.params.label) || ''; const triggerImport = (route.params && route.params.triggerImport) || false; const [importText, setImportText] = useState(label); @@ -67,9 +69,10 @@ const WalletsImport = () => { * @param importText */ const importMnemonic = async importText => { - if (WalletImport.isCurrentlyImportingWallet()) { + if (isImportingWallet && isImportingWallet.isFailure === false) { return; } + WalletImport.addPlaceholderWallet(importText); navigation.dangerouslyGetParent().pop(); await new Promise(resolve => setTimeout(resolve, 500)); // giving some time to animations @@ -77,11 +80,30 @@ const WalletsImport = () => { await WalletImport.processImportText(importText); WalletImport.removePlaceholderWallet(); } catch (error) { - WalletImport.removePlaceholderWallet(); - WalletImport.addPlaceholderWallet(importText, true); console.log(error); - alert(loc.wallets.import_error); ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); + Alert.alert( + loc.wallets.add_details, + loc.wallets.list_import_problem, + [ + { + text: loc.wallets.list_tryagain, + onPress: () => { + navigation.navigate('AddWalletRoot', { screen: 'ImportWallet', params: { label: importText } }); + WalletImport.removePlaceholderWallet(); + }, + style: 'default', + }, + { + text: loc._.cancel, + onPress: () => { + WalletImport.removePlaceholderWallet(); + }, + style: 'cancel', + }, + ], + { cancelable: false }, + ); } }; diff --git a/screen/wallets/list.js b/screen/wallets/list.js index dfc3822ab..79945154b 100644 --- a/screen/wallets/list.js +++ b/screen/wallets/list.js @@ -6,7 +6,6 @@ import { Text, StyleSheet, SectionList, - Alert, Platform, Image, Dimensions, @@ -21,8 +20,6 @@ import WalletsCarousel from '../../components/WalletsCarousel'; import { Icon } from 'react-native-elements'; import DeeplinkSchemaMatch from '../../class/deeplink-schema-match'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; -import { PlaceholderWallet } from '../../class'; -import WalletImport from '../../class/wallet-import'; import ActionSheet from '../ActionSheet'; import loc from '../../loc'; import { FContainer, FButton } from '../../components/FloatButtons'; @@ -39,8 +36,9 @@ const WalletsListSections = { CAROUSEL: 'CAROUSEL', LOCALTRADER: 'LOCALTRADER', const WalletsList = () => { const walletsCarousel = useRef(); + const currentWalletIndex = useRef(0); const colorScheme = useColorScheme(); - const { wallets, pendingWallets, getTransactions, getBalance, refreshAllWalletTransactions, setSelectedWallet } = useContext( + const { wallets, getTransactions, isImportingWallet, getBalance, refreshAllWalletTransactions, setSelectedWallet } = useContext( BlueStorageContext, ); const { width } = useWindowDimensions(); @@ -52,7 +50,6 @@ const WalletsList = () => { const [isLargeScreen, setIsLargeScreen] = useState( Platform.OS === 'android' ? isTablet() : width >= Dimensions.get('screen').width / 2 && (isTablet() || isDesktop), ); - const [carouselData, setCarouselData] = useState([]); const dataSource = getTransactions(null, 10); const walletsCount = useRef(wallets.length); const walletActionButtonsRef = useRef(); @@ -87,13 +84,6 @@ const WalletsList = () => { }, []), ); - useEffect(() => { - const allWallets = wallets.concat(pendingWallets); - const newCarouselData = allWallets.concat(false); - setCarouselData(newCarouselData); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [wallets, pendingWallets]); - useEffect(() => { if (walletsCount.current < wallets.length) { walletsCarousel.current?.scrollToItem({ item: wallets[walletsCount.current] }); @@ -102,11 +92,11 @@ const WalletsList = () => { }, [wallets]); useEffect(() => { - if (pendingWallets.length > 0) { - walletsCarousel.current?.scrollToIndex(carouselData.length - pendingWallets.length); + if (isImportingWallet) { + walletsCarousel.current?.scrollToItem({ item: false }); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [pendingWallets]); + }, [isImportingWallet]); const verifyBalance = () => { if (getBalance() !== 0) { @@ -163,41 +153,15 @@ const WalletsList = () => { const handleClick = index => { console.log('click', index); - const wallet = carouselData[index]; - if (wallet) { - if (wallet.type === PlaceholderWallet.type) { - Alert.alert( - loc.wallets.add_details, - loc.wallets.list_import_problem, - [ - { - text: loc.wallets.details_delete, - onPress: () => { - WalletImport.removePlaceholderWallet(); - }, - style: 'destructive', - }, - { - text: loc.wallets.list_tryagain, - onPress: () => { - navigate('AddWalletRoot', { screen: 'ImportWallet', params: { label: wallet.getSecret() } }); - WalletImport.removePlaceholderWallet(); - }, - style: 'default', - }, - ], - { cancelable: false }, - ); - } else { - const walletID = wallet.getID(); - navigate('WalletTransactions', { - walletID, - walletType: wallet.type, - key: `WalletTransactions-${walletID}`, - }); - } - } else { - // if its out of index - this must be last card with incentive to create wallet + if (index <= wallets.length - 1) { + const wallet = wallets[index]; + const walletID = wallet.getID(); + navigate('WalletTransactions', { + walletID, + walletType: wallet.type, + key: `WalletTransactions-${walletID}`, + }); + } else if (index >= wallets.length && !isImportingWallet) { navigate('AddWalletRoot'); } }; @@ -207,10 +171,16 @@ const WalletsList = () => { const contentOffset = e.nativeEvent.contentOffset; const index = Math.ceil(contentOffset.x / width); - console.log('onSnapToItem', index); - if (wallets[index] && (wallets[index].timeToRefreshBalance() || wallets[index].timeToRefreshTransaction())) { - console.log(wallets[index].getLabel(), 'thinks its time to refresh either balance or transactions. refetching both'); - refreshAllWalletTransactions(index, false).finally(() => setIsLoading(false)); + + if (currentWalletIndex.current !== index) { + console.log('onSnapToItem', wallets.length === index ? 'NewWallet/Importing card' : index); + if (wallets[index] && (wallets[index].timeToRefreshBalance() || wallets[index].timeToRefreshTransaction())) { + console.log(wallets[index].getLabel(), 'thinks its time to refresh either balance or transactions. refetching both'); + refreshAllWalletTransactions(index, false).finally(() => setIsLoading(false)); + } + currentWalletIndex.current = index; + } else { + console.log('onSnapToItem did not change. Most likely momentum stopped at the same index it started.'); } }; @@ -231,7 +201,7 @@ const WalletsList = () => { }; const handleLongPress = () => { - if (carouselData.length > 1 && !carouselData.some(wallet => wallet.type === PlaceholderWallet.type)) { + if (wallets.length > 1 && !isImportingWallet) { navigate('ReorderWallets'); } else { ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); @@ -247,8 +217,8 @@ const WalletsList = () => { }; const renderLocalTrader = () => { - if (carouselData.every(wallet => wallet === false)) return null; - if (carouselData.length > 0 && !carouselData.some(wallet => wallet.type === PlaceholderWallet.type)) { + if (wallets.every(wallet => wallet === false)) return null; + if (wallets.length > 0 && !isImportingWallet) { const button = ( <TouchableOpacity accessibilityRole="button" @@ -272,8 +242,8 @@ const WalletsList = () => { const renderWalletsCarousel = () => { return ( <WalletsCarousel - data={carouselData} - extraData={carouselData} + data={wallets.concat(false)} + extraData={[wallets, isImportingWallet]} onPress={handleClick} handleLongPress={handleLongPress} onMomentumScrollEnd={onSnapToItem} @@ -302,10 +272,7 @@ const WalletsList = () => { switch (section.section.key) { case WalletsListSections.CAROUSEL: return isLargeScreen ? null : ( - <BlueHeaderDefaultMain - leftText={loc.wallets.list_title} - onNewWalletPress={!carouselData.some(wallet => wallet.type === PlaceholderWallet.type) ? () => navigate('AddWalletRoot') : null} - /> + <BlueHeaderDefaultMain leftText={loc.wallets.list_title} onNewWalletPress={() => navigate('AddWalletRoot')} /> ); case WalletsListSections.TRANSACTIONS: return renderListHeaderComponent(); @@ -333,7 +300,7 @@ const WalletsList = () => { }; const renderScanButton = () => { - if (carouselData.length > 0 && !carouselData.some(wallet => wallet.type === PlaceholderWallet.type)) { + if (wallets.length > 0 && isImportingWallet) { return ( <FContainer ref={walletActionButtonsRef}> <FButton