Merge pull request #7604 from BlueWallet/addressfixes

Addressfixes
This commit is contained in:
GLaDOS 2025-02-20 23:07:08 +00:00 committed by GitHub
commit 47673a4ae0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 112 additions and 144 deletions

View file

@ -7,24 +7,18 @@ import { GROUP_IO_BLUEWALLET } from '../blue_modules/currency';
import { BlueApp } from '../class';
import { HandOffComponentProps } from './types';
const HandOffComponent: React.FC<HandOffComponentProps> = React.memo(
props => {
const { isHandOffUseEnabled } = useSettings();
const HandOffComponent: React.FC<HandOffComponentProps> = props => {
const { isHandOffUseEnabled } = useSettings();
if (!props || !props.type || !props.userInfo || Object.keys(props.userInfo).length === 0) {
console.debug('HandOffComponent: Missing required type or userInfo data');
return null;
}
const userInfo = JSON.stringify(props.userInfo);
console.debug(`HandOffComponent is rendering. Type: ${props.type}, UserInfo: ${userInfo}...`);
return isHandOffUseEnabled ? <Handoff {...props} /> : null;
};
if (!props || !props.type || !props.userInfo || Object.keys(props.userInfo).length === 0) {
return null;
}
return isHandOffUseEnabled ? <Handoff {...props} /> : null;
},
(prevProps, nextProps) => {
return (
prevProps.type === nextProps.type &&
JSON.stringify(prevProps.userInfo) === JSON.stringify(nextProps.userInfo) &&
prevProps.title === nextProps.title
);
},
);
const MemoizedHandOffComponent = React.memo(HandOffComponent);
export const setIsHandOffUseEnabled = async (value: boolean) => {
try {
@ -50,4 +44,4 @@ export const getIsHandOffUseEnabled = async (): Promise<boolean> => {
}
};
export default HandOffComponent;
export default MemoizedHandOffComponent;

View file

@ -40,9 +40,7 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
borderBottomColor: colors.lightBorder,
backgroundColor: colors.elevated,
},
list: {
color: colors.buttonTextColor,
},
index: {
color: colors.alternativeTextColor,
},
@ -156,19 +154,23 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
isButton
>
<ListItem key={item.key} containerStyle={stylesHook.container}>
<ListItem.Content style={stylesHook.list}>
<ListItem.Title style={stylesHook.list} numberOfLines={1} ellipsizeMode="middle">
<Text style={[styles.index, stylesHook.index]}>{item.index + 1}</Text>{' '}
<Text style={[stylesHook.address, styles.address]}>{item.address}</Text>
</ListItem.Title>
<View style={styles.subtitle}>
<Text style={[stylesHook.list, styles.balance, stylesHook.balance]}>{balance}</Text>
<ListItem.Content>
<View style={styles.row}>
<View style={styles.leftSection}>
<Text style={[styles.index, stylesHook.index]}>{item.index}</Text>
</View>
<View style={styles.middleSection}>
<Text style={[stylesHook.address, styles.address]} numberOfLines={1} ellipsizeMode="middle">
{item.address}
</Text>
<Text style={[stylesHook.balance, styles.balance]}>{balance}</Text>
</View>
</View>
</ListItem.Content>
<View>
<View style={styles.rightContainer}>
<AddressTypeBadge isInternal={item.isInternal} hasTransactions={hasTransactions} />
<Text style={[stylesHook.list, styles.balance, stylesHook.balance]}>
{loc.addresses.transactions}: {item.transactions}
<Text style={[stylesHook.balance, styles.balance]}>
{loc.addresses.transactions}: {item.transactions ?? 0}
</Text>
</View>
</ListItem>
@ -179,20 +181,27 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
const styles = StyleSheet.create({
address: {
fontWeight: 'bold',
marginHorizontal: 40,
marginHorizontal: 4,
},
index: {
fontSize: 15,
},
balance: {
marginTop: 8,
marginLeft: 14,
marginTop: 4,
},
subtitle: {
flex: 1,
row: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
alignItems: 'center',
},
leftSection: {
marginRight: 8,
},
middleSection: {
flex: 1,
},
rightContainer: {
justifyContent: 'center',
alignItems: 'flex-end',
},
});

View file

@ -31,37 +31,6 @@ import TipBox from '../../components/TipBox';
const segmentControlValues = [loc.wallets.details_address, loc.bip47.payment_code];
const TabContent = React.memo(
({ currentTab, bip21encoded, wallet, address, showAddress, isCustom, handleShareButtonPressed, renderReceiveDetails }) => {
const qrValue = useMemo(
() => (currentTab === segmentControlValues[0] ? bip21encoded : wallet?.getBIP47PaymentCode()),
[currentTab, bip21encoded, wallet],
);
if (currentTab === segmentControlValues[0]) {
return <View style={styles.container}>{address && renderReceiveDetails()}</View>;
} else {
return (
<View style={styles.container}>
{!qrValue && <Text>{loc.bip47.not_found}</Text>}
{qrValue && (
<>
<TipBox description={loc.receive.bip47_explanation} containerStyle={styles.tip} />
<QRCodeComponent value={qrValue} />
<CopyTextToClipboard text={qrValue} truncated={false} />
</>
)}
</View>
);
}
},
);
const MemoizedHandoffComponent = React.memo(
({ address }) => <HandOffComponent title={loc.send.details_address} type={HandOffActivityType.ReceiveOnchain} userInfo={{ address }} />,
(prevProps, nextProps) => prevProps.address === nextProps.address,
);
const ReceiveDetails = () => {
const { walletID, address } = useRoute().params;
const { wallets, saveToDisk, sleep, fetchAndSaveWalletTransactions } = useStorage();
@ -459,37 +428,25 @@ const ReceiveDetails = () => {
}
};
const [isLoading, setIsLoading] = useState(false);
const handleTabChange = useCallback(index => {
setIsLoading(true);
// Use requestAnimationFrame to prevent UI blocking (better than InteractionManager)
requestAnimationFrame(() => {
setCurrentTab(segmentControlValues[index]);
// Add a small delay to allow the UI to update (sadly needed hack)
setTimeout(() => {
setIsLoading(false);
}, 100);
});
}, []);
const renderTabContent = () => {
if (isLoading) {
return <BlueLoading />;
}
const qrValue = currentTab === segmentControlValues[0] ? bip21encoded : wallet.getBIP47PaymentCode();
return (
<TabContent
currentTab={currentTab}
bip21encoded={bip21encoded}
wallet={wallet}
address={address}
showAddress={showAddress}
isCustom={isCustom}
handleShareButtonPressed={handleShareButtonPressed}
renderReceiveDetails={renderReceiveDetails}
/>
);
if (currentTab === segmentControlValues[0]) {
return <View style={styles.container}>{address && renderReceiveDetails()}</View>;
} else {
return (
<View style={styles.container}>
{!qrValue && <Text>{loc.bip47.not_found}</Text>}
{qrValue && (
<>
<TipBox description={loc.receive.bip47_explanation} containerStyle={styles.tip} />
<QRCodeComponent value={qrValue} />
<CopyTextToClipboard text={qrValue} truncated={false} />
</>
)}
</View>
);
}
};
return (
@ -504,12 +461,16 @@ const ReceiveDetails = () => {
<SegmentedControl
values={segmentControlValues}
selectedIndex={segmentControlValues.findIndex(tab => tab === currentTab)}
onChange={handleTabChange}
onChange={index => {
setCurrentTab(segmentControlValues[index]);
}}
/>
</View>
)}
{showAddress && renderTabContent()}
{address !== undefined && showAddress && <MemoizedHandoffComponent address={address} />}
{address !== undefined && showAddress && (
<HandOffComponent title={loc.send.details_address} type={HandOffActivityType.ReceiveOnchain} userInfo={{ address }} />
)}
{showConfirmedBalance ? renderConfirmedBalance() : null}
{showPendingBalance ? renderPendingBalance() : null}
{!showAddress && !showPendingBalance && !showConfirmedBalance ? <BlueLoading /> : null}

View file

@ -139,6 +139,25 @@ const WalletAddresses: React.FC = () => {
},
});
const getAddresses = useMemo(() => {
if (!walletInstance) return [];
const newAddresses: Address[] = [];
// @ts-ignore: idk what to do
for (let index = 0; index <= (walletInstance?.next_free_change_address_index ?? 0); index++) {
newAddresses.push(getAddress(walletInstance, index, true));
}
// @ts-ignore: idk what to do
for (let index = 0; index < (walletInstance?.next_free_address_index ?? 0) + (walletInstance?.gap_limit ?? 0); index++) {
newAddresses.push(getAddress(walletInstance, index, false));
}
return newAddresses;
}, [walletInstance]);
useEffect(() => {
dispatch({ type: SET_ADDRESSES, payload: getAddresses });
dispatch({ type: SET_SHOW_ADDRESSES, payload: true });
}, [getAddresses]);
const filteredAddresses = useMemo(
() => addresses.filter(address => filterByAddressType(TABS.INTERNAL, address.isInternal, currentTab)).sort(sortByAddressIndex),
[addresses, currentTab],
@ -158,36 +177,20 @@ const WalletAddresses: React.FC = () => {
});
}, [setOptions]);
const getAddresses = useCallback(() => {
const newAddresses: Address[] = [];
// @ts-ignore: idk what to do
for (let index = 0; index <= (walletInstance?.next_free_change_address_index ?? 0); index++) {
const address = getAddress(walletInstance, index, true);
newAddresses.push(address);
}
// @ts-ignore: idk what to do
for (let index = 0; index < (walletInstance?.next_free_address_index ?? 0) + (walletInstance?.gap_limit ?? 0); index++) {
const address = getAddress(walletInstance, index, false);
newAddresses.push(address);
}
dispatch({ type: SET_ADDRESSES, payload: newAddresses });
dispatch({ type: SET_SHOW_ADDRESSES, payload: true });
}, [walletInstance]);
useFocusEffect(
useCallback(() => {
if (!isDesktop) disallowScreenshot(true);
getAddresses();
return () => {
if (!isDesktop) disallowScreenshot(false);
};
}, [getAddresses]),
}, []),
);
const data =
search.length > 0 ? filteredAddresses.filter(item => item.address.toLowerCase().includes(search.toLowerCase())) : filteredAddresses;
const keyExtractor = useCallback((item: Address) => item.key, []);
const renderRow = useCallback(
({ item }: { item: Address }) => {
return (
@ -206,31 +209,32 @@ const WalletAddresses: React.FC = () => {
}
return (
<View style={[styles.root, stylesHook.root]}>
<FlatList
contentContainerStyle={stylesHook.root}
ref={addressList}
data={data}
extraData={data}
initialNumToRender={20}
renderItem={renderRow}
ListEmptyComponent={search.length > 0 ? null : <ActivityIndicator />}
centerContent={!showAddresses}
contentInsetAdjustmentBehavior="automatic"
ListHeaderComponent={
<SegmentedControl
values={Object.values(TABS).map(tab => loc.addresses[`type_${tab}`])}
selectedIndex={Object.values(TABS).findIndex(tab => tab === currentTab)}
onChange={index => {
const tabKey = Object.keys(TABS)[index] as TabKey;
dispatch({ type: SET_CURRENT_TAB, payload: TABS[tabKey] });
}}
// style={{ marginVertical: 10 }}
/>
}
/>
</View>
<FlatList
contentContainerStyle={stylesHook.root}
ref={addressList}
data={data}
extraData={data}
style={styles.root}
keyExtractor={keyExtractor}
initialNumToRender={20}
renderItem={renderRow}
ListEmptyComponent={search.length > 0 ? null : <ActivityIndicator />}
centerContent={!showAddresses}
contentInsetAdjustmentBehavior="automatic"
automaticallyAdjustContentInsets
automaticallyAdjustsScrollIndicatorInsets
automaticallyAdjustKeyboardInsets
ListHeaderComponent={
<SegmentedControl
values={Object.values(TABS).map(tab => loc.addresses[`type_${tab}`])}
selectedIndex={Object.values(TABS).findIndex(tab => tab === currentTab)}
onChange={index => {
const tabKey = Object.keys(TABS)[index] as TabKey;
dispatch({ type: SET_CURRENT_TAB, payload: TABS[tabKey] });
}}
/>
}
/>
);
};