mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-12 18:51:21 +01:00
wip
This commit is contained in:
parent
ecfd52393e
commit
9a31d729f4
3 changed files with 170 additions and 145 deletions
|
@ -105,11 +105,128 @@ interface WalletCarouselItemProps {
|
|||
customStyle?: ViewStyle;
|
||||
horizontal?: boolean;
|
||||
isActive?: boolean;
|
||||
allowOnPressAnimation?: boolean;
|
||||
searchQuery?: string;
|
||||
renderHighlightedText?: (text: string, query: string) => JSX.Element;
|
||||
}
|
||||
|
||||
export const WalletCarouselItem: React.FC<WalletCarouselItemProps> = ({
|
||||
item,
|
||||
onPress,
|
||||
handleLongPress,
|
||||
isSelectedWallet,
|
||||
customStyle,
|
||||
horizontal,
|
||||
isActive,
|
||||
searchQuery,
|
||||
renderHighlightedText,
|
||||
}) => {
|
||||
const scaleValue = useRef(new Animated.Value(1.0)).current;
|
||||
const { colors } = useTheme();
|
||||
const { width } = useWindowDimensions();
|
||||
const itemWidth = width * 0.82 > 375 ? 375 : width * 0.82;
|
||||
const isLargeScreen = useIsLargeScreen();
|
||||
|
||||
const onPressedIn = useCallback(() => {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 0.95,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}, [scaleValue]);
|
||||
|
||||
const onPressedOut = useCallback(() => {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 1.0,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}, [scaleValue]);
|
||||
|
||||
const handlePress = useCallback(() => {
|
||||
onPressedOut();
|
||||
onPress(item);
|
||||
}, [item, onPress, onPressedOut]);
|
||||
|
||||
const opacity = isSelectedWallet === false ? 0.5 : 1.0;
|
||||
let image;
|
||||
switch (item.type) {
|
||||
case LightningLdkWallet.type:
|
||||
case LightningCustodianWallet.type:
|
||||
image = I18nManager.isRTL ? require('../img/lnd-shape-rtl.png') : require('../img/lnd-shape.png');
|
||||
break;
|
||||
case MultisigHDWallet.type:
|
||||
image = I18nManager.isRTL ? require('../img/vault-shape-rtl.png') : require('../img/vault-shape.png');
|
||||
break;
|
||||
default:
|
||||
image = I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png');
|
||||
}
|
||||
|
||||
const latestTransactionText =
|
||||
item.getBalance() !== 0 && item.getLatestTransactionTime() === 0
|
||||
? loc.wallets.pull_to_refresh
|
||||
: item.getTransactions().find((tx: Transaction) => tx.confirmations === 0)
|
||||
? loc.transactions.pending
|
||||
: transactionTimeToReadable(item.getLatestTransactionTime());
|
||||
|
||||
const balance = !item.hideBalance && formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit(), true);
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
isLargeScreen || !horizontal ? [iStyles.rootLargeDevice, customStyle] : customStyle ?? { ...iStyles.root, width: itemWidth },
|
||||
{ opacity, transform: [{ scale: scaleValue }] },
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
testID={item.getLabel()}
|
||||
onPressIn={onPressedIn}
|
||||
onPressOut={onPressedOut}
|
||||
onLongPress={() => {
|
||||
if (handleLongPress) handleLongPress();
|
||||
}}
|
||||
onPress={handlePress}
|
||||
>
|
||||
<View style={[iStyles.shadowContainer, { backgroundColor: colors.background, shadowColor: colors.shadowColor }]}>
|
||||
<LinearGradient colors={WalletGradient.gradientsFor(item.type)} style={iStyles.grad}>
|
||||
<Image source={image} style={iStyles.image} />
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.label, { color: colors.inverseForegroundColor }]}>
|
||||
{renderHighlightedText && searchQuery ? renderHighlightedText(item.getLabel(), searchQuery) : item.getLabel()}
|
||||
</Text>
|
||||
<View style={iStyles.balanceContainer}>
|
||||
{item.hideBalance ? (
|
||||
<>
|
||||
<BlueSpacing10 />
|
||||
<BlurredBalanceView />
|
||||
</>
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
adjustsFontSizeToFit
|
||||
key={`${balance}`} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||
style={[iStyles.balance, { color: colors.inverseForegroundColor }]}
|
||||
>
|
||||
{`${balance} `}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.latestTx, { color: colors.inverseForegroundColor }]}>
|
||||
{loc.wallets.list_latest_transaction}
|
||||
</Text>
|
||||
<Text numberOfLines={1} style={[iStyles.latestTxTime, { color: colors.inverseForegroundColor }]}>
|
||||
{latestTransactionText}
|
||||
</Text>
|
||||
</LinearGradient>
|
||||
</View>
|
||||
</Pressable>
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
|
||||
const iStyles = StyleSheet.create({
|
||||
root: { paddingRight: 20 },
|
||||
rootLargeDevice: { marginVertical: 20 },
|
||||
|
@ -169,129 +286,6 @@ const iStyles = StyleSheet.create({
|
|||
},
|
||||
});
|
||||
|
||||
export const WalletCarouselItem: React.FC<WalletCarouselItemProps> = React.memo(
|
||||
({
|
||||
item,
|
||||
onPress,
|
||||
handleLongPress,
|
||||
isSelectedWallet,
|
||||
customStyle,
|
||||
horizontal,
|
||||
allowOnPressAnimation = true,
|
||||
searchQuery,
|
||||
renderHighlightedText,
|
||||
}) => {
|
||||
const scaleValue = useRef(new Animated.Value(1.0)).current;
|
||||
const { colors } = useTheme();
|
||||
const { walletTransactionUpdateStatus } = useStorage();
|
||||
const { width } = useWindowDimensions();
|
||||
const itemWidth = width * 0.82 > 375 ? 375 : width * 0.82;
|
||||
const isLargeScreen = useIsLargeScreen();
|
||||
|
||||
const onPressedIn = useCallback(() => {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 0.95,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}, [scaleValue]);
|
||||
|
||||
const onPressedOut = useCallback(() => {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 1.0,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}, [scaleValue]);
|
||||
|
||||
const handlePress = useCallback(() => {
|
||||
onPressedOut();
|
||||
onPress(item);
|
||||
}, [item, onPress, onPressedOut]);
|
||||
|
||||
const opacity = isSelectedWallet === false ? 0.5 : 1.0;
|
||||
let image;
|
||||
switch (item.type) {
|
||||
case LightningLdkWallet.type:
|
||||
case LightningCustodianWallet.type:
|
||||
image = I18nManager.isRTL ? require('../img/lnd-shape-rtl.png') : require('../img/lnd-shape.png');
|
||||
break;
|
||||
case MultisigHDWallet.type:
|
||||
image = I18nManager.isRTL ? require('../img/vault-shape-rtl.png') : require('../img/vault-shape.png');
|
||||
break;
|
||||
default:
|
||||
image = I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png');
|
||||
}
|
||||
|
||||
const latestTransactionText =
|
||||
walletTransactionUpdateStatus === WalletTransactionsStatus.ALL || walletTransactionUpdateStatus === item.getID()
|
||||
? loc.transactions.updating
|
||||
: item.getBalance() !== 0 && item.getLatestTransactionTime() === 0
|
||||
? loc.wallets.pull_to_refresh
|
||||
: item.getTransactions().find((tx: Transaction) => tx.confirmations === 0)
|
||||
? loc.transactions.pending
|
||||
: transactionTimeToReadable(item.getLatestTransactionTime());
|
||||
|
||||
const balance = !item.hideBalance && formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit(), true);
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
isLargeScreen || !horizontal ? [iStyles.rootLargeDevice, customStyle] : customStyle ?? { ...iStyles.root, width: itemWidth },
|
||||
{ opacity, transform: [{ scale: scaleValue }] },
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
testID={item.getLabel()}
|
||||
onPressIn={allowOnPressAnimation ? onPressedIn : undefined}
|
||||
onPressOut={allowOnPressAnimation ? onPressedOut : undefined}
|
||||
onLongPress={() => {
|
||||
if (handleLongPress) handleLongPress();
|
||||
}}
|
||||
onPress={handlePress}
|
||||
>
|
||||
<View style={[iStyles.shadowContainer, { backgroundColor: colors.background, shadowColor: colors.shadowColor }]}>
|
||||
<LinearGradient colors={WalletGradient.gradientsFor(item.type)} style={iStyles.grad}>
|
||||
<Image source={image} style={iStyles.image} />
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.label, { color: colors.inverseForegroundColor }]}>
|
||||
{renderHighlightedText ? renderHighlightedText(item.getLabel(), searchQuery ?? '') : item.getLabel()}
|
||||
</Text>
|
||||
<View style={iStyles.balanceContainer}>
|
||||
{item.hideBalance ? (
|
||||
<>
|
||||
<BlueSpacing10 />
|
||||
<BlurredBalanceView />
|
||||
</>
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
adjustsFontSizeToFit
|
||||
key={`${balance}`} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||
style={[iStyles.balance, { color: colors.inverseForegroundColor }]}
|
||||
>
|
||||
{`${balance} `}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.latestTx, { color: colors.inverseForegroundColor }]}>
|
||||
{loc.wallets.list_latest_transaction}
|
||||
</Text>
|
||||
<Text numberOfLines={1} style={[iStyles.latestTxTime, { color: colors.inverseForegroundColor }]}>
|
||||
{latestTransactionText}
|
||||
</Text>
|
||||
</LinearGradient>
|
||||
</View>
|
||||
</Pressable>
|
||||
</Animated.View>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
interface WalletsCarouselProps extends Partial<FlatListProps<any>> {
|
||||
horizontal?: boolean;
|
||||
selectedWallet?: string;
|
||||
|
@ -300,7 +294,8 @@ interface WalletsCarouselProps extends Partial<FlatListProps<any>> {
|
|||
handleLongPress?: () => void;
|
||||
data: TWallet[];
|
||||
scrollEnabled?: boolean;
|
||||
showNewWalletPanel?: boolean; // New prop
|
||||
renderHighlightedText?: (text: string, query: string) => JSX.Element;
|
||||
searchQuery?: string;
|
||||
}
|
||||
|
||||
type FlatListRefType = FlatList<any> & {
|
||||
|
@ -329,7 +324,17 @@ const cStyles = StyleSheet.create({
|
|||
const ListHeaderComponent: React.FC = () => <View style={cStyles.separatorStyle} />;
|
||||
|
||||
const WalletsCarousel = forwardRef<FlatListRefType, WalletsCarouselProps>((props, ref) => {
|
||||
const { horizontal, data, handleLongPress, onPress, selectedWallet, scrollEnabled, showNewWalletPanel, onNewWalletPress } = props;
|
||||
const {
|
||||
horizontal,
|
||||
data,
|
||||
handleLongPress,
|
||||
onPress,
|
||||
selectedWallet,
|
||||
scrollEnabled,
|
||||
onNewWalletPress,
|
||||
searchQuery,
|
||||
renderHighlightedText,
|
||||
} = props;
|
||||
const renderItem = useCallback(
|
||||
({ item, index }: ListRenderItemInfo<TWallet>) =>
|
||||
item ? (
|
||||
|
@ -339,9 +344,11 @@ const WalletsCarousel = forwardRef<FlatListRefType, WalletsCarouselProps>((props
|
|||
handleLongPress={handleLongPress}
|
||||
onPress={onPress}
|
||||
horizontal={horizontal}
|
||||
searchQuery={searchQuery}
|
||||
renderHighlightedText={renderHighlightedText}
|
||||
/>
|
||||
) : null,
|
||||
[horizontal, selectedWallet, handleLongPress, onPress],
|
||||
[horizontal, selectedWallet, handleLongPress, onPress, searchQuery, renderHighlightedText],
|
||||
);
|
||||
|
||||
const flatListRef = useRef<FlatList<any>>(null);
|
||||
|
@ -406,7 +413,7 @@ const WalletsCarousel = forwardRef<FlatListRefType, WalletsCarouselProps>((props
|
|||
ListHeaderComponent={ListHeaderComponent}
|
||||
style={{ minHeight: sliderHeight + 12 }}
|
||||
onScrollToIndexFailed={onScrollToIndexFailed}
|
||||
ListFooterComponent={showNewWalletPanel && onNewWalletPress ? <NewWalletPanel onPress={onNewWalletPress} /> : null}
|
||||
ListFooterComponent={onNewWalletPress ? <NewWalletPanel onPress={onNewWalletPress} /> : null}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
|
@ -419,10 +426,12 @@ const WalletsCarousel = forwardRef<FlatListRefType, WalletsCarouselProps>((props
|
|||
handleLongPress={handleLongPress}
|
||||
onPress={onPress}
|
||||
key={index}
|
||||
searchQuery={props.searchQuery}
|
||||
renderHighlightedText={props.renderHighlightedText}
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
{showNewWalletPanel && onNewWalletPress && <NewWalletPanel onPress={onNewWalletPress} />}
|
||||
{onNewWalletPress && <NewWalletPanel onPress={onNewWalletPress} />}
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -496,7 +496,7 @@
|
|||
"add_ln_wallet_first": "You must first add a Lightning wallet.",
|
||||
"identity_pubkey": "Identity Pubkey",
|
||||
"xpub_title": "Wallet XPUB",
|
||||
"search_wallets": "Search wallets, memos, and transactions"
|
||||
"search_wallets": "Search wallets, memos"
|
||||
},
|
||||
"multisig": {
|
||||
"multisig_vault": "Vault",
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React, { useEffect, useLayoutEffect, useRef, useReducer, useCallback, useMemo } from 'react';
|
||||
import { Platform, StyleSheet, useColorScheme, TouchableOpacity, Image, Animated, Text, I18nManager } from 'react-native';
|
||||
import { Platform, StyleSheet, useColorScheme, TouchableOpacity, Image, Animated, Text, I18nManager, View } from 'react-native';
|
||||
// @ts-ignore: no declaration file
|
||||
import DraggableFlatList, { ScaleDecorator } from 'react-native-draggable-flatlist';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { WalletCarouselItem } from '../../components/WalletsCarousel';
|
||||
import { TransactionListItem } from '../../components/TransactionListItem';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import loc from '../../loc';
|
||||
|
@ -14,6 +13,8 @@ import useDebounce from '../../hooks/useDebounce';
|
|||
import { Header } from '../../components/Header';
|
||||
import { TTXMetadata } from '../../class';
|
||||
import { TWallet } from '../../class/wallets/types';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import { WalletCarouselItem } from '../../components/WalletsCarousel';
|
||||
|
||||
const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY';
|
||||
const SET_IS_SEARCH_FOCUSED = 'SET_IS_SEARCH_FOCUSED';
|
||||
|
@ -86,19 +87,21 @@ const useBounceAnimation = (query: string) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (query) {
|
||||
Animated.timing(bounceAnim, {
|
||||
Animated.spring(bounceAnim, {
|
||||
toValue: 1.2,
|
||||
duration: 150,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start(() => {
|
||||
Animated.timing(bounceAnim, {
|
||||
Animated.spring(bounceAnim, {
|
||||
toValue: 1.0,
|
||||
duration: 150,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
}, [bounceAnim, query]);
|
||||
}, [query]);
|
||||
|
||||
return bounceAnim;
|
||||
};
|
||||
|
@ -238,13 +241,16 @@ const ManageWallets: React.FC = () => {
|
|||
|
||||
if (item.type === 'transaction') {
|
||||
return (
|
||||
<TransactionListItem
|
||||
item={item.data}
|
||||
itemPriceUnit="BTC"
|
||||
walletID={item.data.walletID}
|
||||
searchQuery={state.searchQuery}
|
||||
style={StyleSheet.flatten([styles.padding16, { opacity: itemOpacity }])}
|
||||
/>
|
||||
<View style={StyleSheet.flatten([styles.padding16, { opacity: itemOpacity }])}>
|
||||
<TransactionListItem
|
||||
item={item.data}
|
||||
// update later to support other units
|
||||
itemPriceUnit={BitcoinUnit.BTC}
|
||||
walletID={item.data.walletID}
|
||||
searchQuery={state.searchQuery}
|
||||
renderHighlightedText={renderHighlightedText}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -292,7 +298,9 @@ const ManageWallets: React.FC = () => {
|
|||
<>
|
||||
{hasWallets && <Header leftText={loc.wallets.wallets} isDrawerList />}
|
||||
{hasTransactions && <Header leftText={loc.addresses.transactions} isDrawerList />}
|
||||
{!hasWallets && !hasTransactions && <Text style={stylesHook.noResultsText}>{loc.wallets.no_results_found}</Text>}
|
||||
{!hasWallets && !hasTransactions && (
|
||||
<Text style={[styles.noResultsText, stylesHook.noResultsText]}>{loc.wallets.no_results_found}</Text>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}, [state.searchQuery, state.walletData.length, state.txMetadata, stylesHook.noResultsText]);
|
||||
|
@ -329,6 +337,14 @@ const styles = StyleSheet.create({
|
|||
button: {
|
||||
padding: 16,
|
||||
},
|
||||
noResultsText: {
|
||||
fontSize: 19,
|
||||
fontWeight: 'bold',
|
||||
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 34,
|
||||
},
|
||||
});
|
||||
|
||||
const iStyles = StyleSheet.create({
|
||||
|
|
Loading…
Add table
Reference in a new issue