mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-13 19:16:52 +01:00
227 lines
7.1 KiB
TypeScript
227 lines
7.1 KiB
TypeScript
import React, { useCallback, useState, useEffect, useRef } from 'react';
|
|
import { StyleSheet, ViewStyle, TouchableOpacity, ActivityIndicator, Platform, Animated } from 'react-native';
|
|
import { Icon, ListItem } from '@rneui/base';
|
|
import { ExtendedTransaction, LightningTransaction, TWallet } from '../class/wallets/types';
|
|
import { WalletCarouselItem } from './WalletsCarousel';
|
|
import { TransactionListItem } from './TransactionListItem';
|
|
import { useTheme } from './themes';
|
|
import { BitcoinUnit } from '../models/bitcoinUnits';
|
|
import loc from '../loc';
|
|
import triggerHapticFeedback, { HapticFeedbackTypes } from '../blue_modules/hapticFeedback';
|
|
|
|
enum ItemType {
|
|
WalletSection = 'wallet',
|
|
TransactionSection = 'transaction',
|
|
}
|
|
|
|
interface WalletItem {
|
|
type: ItemType.WalletSection;
|
|
data: TWallet;
|
|
}
|
|
|
|
interface TransactionItem {
|
|
type: ItemType.TransactionSection;
|
|
data: ExtendedTransaction & LightningTransaction;
|
|
}
|
|
|
|
type Item = WalletItem | TransactionItem;
|
|
|
|
interface ManageWalletsListItemProps {
|
|
item: Item;
|
|
isDraggingDisabled: boolean;
|
|
drag?: () => void;
|
|
isPlaceHolder?: boolean;
|
|
onPressIn?: () => void;
|
|
onPressOut?: () => void;
|
|
state: { wallets: TWallet[]; searchQuery: string };
|
|
navigateToWallet: (wallet: TWallet) => void;
|
|
renderHighlightedText: (text: string, query: string) => JSX.Element;
|
|
handleDeleteWallet: (wallet: TWallet) => void;
|
|
handleToggleHideBalance: (wallet: TWallet) => void;
|
|
isActive?: boolean;
|
|
style?: ViewStyle;
|
|
globalDragActive?: boolean;
|
|
}
|
|
|
|
interface SwipeContentProps {
|
|
onPress: () => void;
|
|
hideBalance?: boolean;
|
|
colors: any;
|
|
}
|
|
|
|
const LeftSwipeContent: React.FC<SwipeContentProps> = ({ onPress, hideBalance, colors }) => (
|
|
<TouchableOpacity
|
|
onPress={onPress}
|
|
style={[styles.leftButtonContainer, { backgroundColor: colors.buttonAlternativeTextColor } as ViewStyle]}
|
|
accessibilityRole="button"
|
|
accessibilityLabel={hideBalance ? loc.transactions.details_balance_show : loc.transactions.details_balance_hide}
|
|
>
|
|
<Icon name={hideBalance ? 'eye-slash' : 'eye'} color={colors.brandingColor} type="font-awesome-5" />
|
|
</TouchableOpacity>
|
|
);
|
|
|
|
const RightSwipeContent: React.FC<Partial<SwipeContentProps>> = ({ onPress }) => (
|
|
<TouchableOpacity
|
|
onPress={onPress}
|
|
style={styles.rightButtonContainer as ViewStyle}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Delete Wallet"
|
|
>
|
|
<Icon name={Platform.OS === 'android' ? 'delete' : 'delete-outline'} color="#FFFFFF" />
|
|
</TouchableOpacity>
|
|
);
|
|
|
|
const ManageWalletsListItem: React.FC<ManageWalletsListItemProps> = ({
|
|
item,
|
|
isDraggingDisabled,
|
|
drag,
|
|
state,
|
|
isPlaceHolder = false,
|
|
navigateToWallet,
|
|
renderHighlightedText,
|
|
handleDeleteWallet,
|
|
handleToggleHideBalance,
|
|
onPressIn,
|
|
onPressOut,
|
|
isActive,
|
|
globalDragActive,
|
|
style,
|
|
}) => {
|
|
const { colors } = useTheme();
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const CARD_SORT_ACTIVE = 1.06;
|
|
const INACTIVE_SCALE_WHEN_ACTIVE = 0.9;
|
|
const SCALE_DURATION = 200;
|
|
const scaleValue = useRef(new Animated.Value(1)).current;
|
|
const prevIsActive = useRef(isActive);
|
|
|
|
const DEFAULT_VERTICAL_MARGIN = -10;
|
|
const REDUCED_VERTICAL_MARGIN = -50;
|
|
|
|
useEffect(() => {
|
|
if (isActive !== prevIsActive.current) {
|
|
triggerHapticFeedback(HapticFeedbackTypes.ImpactMedium);
|
|
}
|
|
prevIsActive.current = isActive;
|
|
|
|
Animated.timing(scaleValue, {
|
|
toValue: isActive ? CARD_SORT_ACTIVE : globalDragActive ? INACTIVE_SCALE_WHEN_ACTIVE : 1,
|
|
duration: SCALE_DURATION,
|
|
useNativeDriver: true,
|
|
}).start();
|
|
}, [isActive, globalDragActive, scaleValue]);
|
|
|
|
const onPress = useCallback(() => {
|
|
if (item.type === ItemType.WalletSection) {
|
|
setIsLoading(true);
|
|
navigateToWallet(item.data);
|
|
setIsLoading(false);
|
|
}
|
|
}, [item, navigateToWallet]);
|
|
|
|
const handleLeftPress = (reset: () => void) => {
|
|
handleToggleHideBalance(item.data as TWallet);
|
|
reset();
|
|
};
|
|
|
|
const leftContent = (reset: () => void) => (
|
|
<LeftSwipeContent onPress={() => handleLeftPress(reset)} hideBalance={(item.data as TWallet).hideBalance} colors={colors} />
|
|
);
|
|
|
|
const handleRightPress = (reset: () => void) => {
|
|
handleDeleteWallet(item.data as TWallet);
|
|
reset();
|
|
};
|
|
|
|
const rightContent = (reset: () => void) => <RightSwipeContent onPress={() => handleRightPress(reset)} />;
|
|
|
|
const startDrag = useCallback(() => {
|
|
scaleValue.setValue(CARD_SORT_ACTIVE);
|
|
triggerHapticFeedback(HapticFeedbackTypes.ImpactMedium);
|
|
if (drag) {
|
|
drag();
|
|
}
|
|
}, [CARD_SORT_ACTIVE, drag, scaleValue]);
|
|
|
|
if (isLoading) {
|
|
return <ActivityIndicator size="large" color={colors.brandingColor} />;
|
|
}
|
|
|
|
if (item.type === ItemType.WalletSection) {
|
|
const animatedStyle = {
|
|
transform: [{ scale: scaleValue }],
|
|
marginVertical: globalDragActive && !isActive ? REDUCED_VERTICAL_MARGIN : DEFAULT_VERTICAL_MARGIN,
|
|
};
|
|
|
|
const backgroundColor = isActive || globalDragActive ? colors.brandingColor : colors.background;
|
|
return (
|
|
<Animated.View style={animatedStyle}>
|
|
<ListItem.Swipeable
|
|
leftWidth={80}
|
|
rightWidth={90}
|
|
containerStyle={[style, { backgroundColor }, isActive || globalDragActive ? styles.transparentBackground : {}]}
|
|
leftContent={globalDragActive ? null : isActive ? null : leftContent}
|
|
rightContent={globalDragActive ? null : isActive ? null : rightContent}
|
|
onPressOut={onPressOut}
|
|
minSlideWidth={80}
|
|
onPressIn={onPressIn}
|
|
style={isActive || globalDragActive ? styles.transparentBackground : {}}
|
|
>
|
|
<ListItem.Content>
|
|
<WalletCarouselItem
|
|
item={item.data}
|
|
handleLongPress={isDraggingDisabled ? undefined : startDrag}
|
|
onPress={onPress}
|
|
onPressIn={onPressIn}
|
|
onPressOut={onPressOut}
|
|
animationsEnabled={false}
|
|
searchQuery={state.searchQuery}
|
|
isPlaceHolder={isPlaceHolder}
|
|
renderHighlightedText={renderHighlightedText}
|
|
customStyle={styles.carouselItem}
|
|
/>
|
|
</ListItem.Content>
|
|
</ListItem.Swipeable>
|
|
</Animated.View>
|
|
);
|
|
} else if (item.type === ItemType.TransactionSection && item.data) {
|
|
const w = state.wallets.find(wallet => wallet.getTransactions().some((tx: ExtendedTransaction) => tx.hash === item.data.hash));
|
|
const walletID = w ? w.getID() : '';
|
|
|
|
return (
|
|
<TransactionListItem
|
|
item={item.data}
|
|
itemPriceUnit={item.data.walletPreferredBalanceUnit || BitcoinUnit.BTC}
|
|
walletID={walletID}
|
|
searchQuery={state.searchQuery}
|
|
renderHighlightedText={renderHighlightedText}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
leftButtonContainer: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
carouselItem: {
|
|
width: '100%',
|
|
},
|
|
rightButtonContainer: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
backgroundColor: 'red',
|
|
},
|
|
transparentBackground: {
|
|
backgroundColor: 'transparent',
|
|
},
|
|
});
|
|
|
|
export { LeftSwipeContent, RightSwipeContent };
|
|
export default ManageWalletsListItem;
|