mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-13 19:16:52 +01:00
Merge pull request #7577 from BlueWallet/notifre
FIX: Alert the user if notifications deregister failed
This commit is contained in:
commit
ae80cb9118
4 changed files with 98 additions and 47 deletions
|
@ -8,7 +8,7 @@ import loc from '../../loc';
|
|||
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { startAndDecrypt } from '../../blue_modules/start-and-decrypt';
|
||||
import { majorTomToGroundControl } from '../../blue_modules/notifications';
|
||||
import { isNotificationsEnabled, majorTomToGroundControl, unsubscribe } from '../../blue_modules/notifications';
|
||||
|
||||
const BlueApp = BlueAppClass.getInstance();
|
||||
|
||||
|
@ -49,6 +49,7 @@ interface StorageContextType {
|
|||
cachedPassword: typeof BlueApp.cachedPassword;
|
||||
getItem: typeof BlueApp.getItem;
|
||||
setItem: typeof BlueApp.setItem;
|
||||
handleWalletDeletion: (walletID: string, forceDelete?: boolean) => Promise<void>;
|
||||
}
|
||||
|
||||
export enum WalletTransactionsStatus {
|
||||
|
@ -99,6 +100,57 @@ export const StorageProvider = ({ children }: { children: React.ReactNode }) =>
|
|||
setWallets([...BlueApp.getWallets()]);
|
||||
}, []);
|
||||
|
||||
const handleWalletDeletion = useCallback(
|
||||
async (walletID: string, forceDelete = false) => {
|
||||
const wallet = wallets.find(w => w.getID() === walletID);
|
||||
if (!wallet) return;
|
||||
|
||||
try {
|
||||
const isNotificationsSettingsEnabled = await isNotificationsEnabled();
|
||||
if (isNotificationsSettingsEnabled) {
|
||||
const externalAddresses = wallet.getAllExternalAddresses();
|
||||
if (externalAddresses.length > 0) {
|
||||
await unsubscribe(externalAddresses, [], []);
|
||||
}
|
||||
}
|
||||
deleteWallet(wallet);
|
||||
saveToDisk(true);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||
} catch (e: unknown) {
|
||||
console.error(e);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
if (forceDelete) {
|
||||
deleteWallet(wallet);
|
||||
saveToDisk(true);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||
} else {
|
||||
presentAlert({
|
||||
title: loc.errors.error,
|
||||
message: loc.wallets.details_delete_wallet_error_message,
|
||||
buttons: [
|
||||
{
|
||||
text: loc.wallets.details_delete_anyway,
|
||||
onPress: () => handleWalletDeletion(walletID, true),
|
||||
style: 'destructive',
|
||||
},
|
||||
{
|
||||
text: loc.wallets.list_tryagain,
|
||||
onPress: () => handleWalletDeletion(walletID),
|
||||
},
|
||||
{
|
||||
text: loc._.cancel,
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
],
|
||||
options: { cancelable: false },
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[deleteWallet, saveToDisk, wallets],
|
||||
);
|
||||
|
||||
const resetWallets = useCallback(() => {
|
||||
setWallets(BlueApp.getWallets());
|
||||
}, []);
|
||||
|
@ -274,6 +326,7 @@ export const StorageProvider = ({ children }: { children: React.ReactNode }) =>
|
|||
isPasswordInUse: BlueApp.isPasswordInUse,
|
||||
walletTransactionUpdateStatus,
|
||||
setWalletTransactionUpdateStatus,
|
||||
handleWalletDeletion,
|
||||
}),
|
||||
[
|
||||
wallets,
|
||||
|
@ -292,6 +345,7 @@ export const StorageProvider = ({ children }: { children: React.ReactNode }) =>
|
|||
resetWallets,
|
||||
walletTransactionUpdateStatus,
|
||||
setWalletTransactionUpdateStatus,
|
||||
handleWalletDeletion,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
@ -422,7 +422,6 @@
|
|||
"details_export_history": "Export History to CSV",
|
||||
"details_master_fingerprint": "Master Fingerprint",
|
||||
"details_multisig_type": "multisig",
|
||||
"details_no_cancel": "No, cancel",
|
||||
"details_show_xpub": "Show Wallet XPUB",
|
||||
"details_show_addresses": "Show addresses",
|
||||
"details_title": "Wallet",
|
||||
|
@ -493,7 +492,9 @@
|
|||
"identity_pubkey": "Identity Pubkey",
|
||||
"xpub_title": "Wallet XPUB",
|
||||
"manage_wallets_search_placeholder": "Search wallets, memos",
|
||||
"more_info": "More Info"
|
||||
"more_info": "More Info",
|
||||
"details_delete_wallet_error_message": "There was an issue confirming if this wallet was removed from notifications—this could be due to a network issue or poor connection. If you continue, you might still receive notifications for transactions related to this wallet, even after it is deleted.",
|
||||
"details_delete_anyway": "Delete anyway"
|
||||
},
|
||||
"total_balance_view": {
|
||||
"display_in_bitcoin": "Display in Bitcoin",
|
||||
|
|
|
@ -16,7 +16,7 @@ import { useFocusEffect, useNavigation } from '@react-navigation/native';
|
|||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import loc from '../../loc';
|
||||
import loc, { formatBalanceWithoutSuffix } from '../../loc';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import useDebounce from '../../hooks/useDebounce';
|
||||
import { TTXMetadata } from '../../class';
|
||||
|
@ -28,6 +28,7 @@ import prompt from '../../helpers/prompt';
|
|||
import HeaderRightButton from '../../components/HeaderRightButton';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import DragList, { DragListRenderItemInfo } from 'react-native-draglist';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
|
||||
const ManageWalletsListItem = lazy(() => import('../../components/ManageWalletsListItem'));
|
||||
|
||||
|
@ -193,7 +194,7 @@ const reducer = (state: State, action: Action): State => {
|
|||
|
||||
const ManageWallets: React.FC = () => {
|
||||
const { colors, closeImage } = useTheme();
|
||||
const { wallets: storedWallets, setWalletsWithNewOrder, txMetadata } = useStorage();
|
||||
const { wallets: storedWallets, setWalletsWithNewOrder, txMetadata, handleWalletDeletion } = useStorage();
|
||||
const { setIsDrawerShouldHide } = useSettings();
|
||||
const walletsRef = useRef<TWallet[]>(deepCopyWallets(storedWallets)); // Create a deep copy of wallets for the DraggableFlatList
|
||||
const { navigate, setOptions, goBack } = useExtendedNavigation();
|
||||
|
@ -242,6 +243,12 @@ const ManageWallets: React.FC = () => {
|
|||
|
||||
walletsRef.current = deepCopyWallets(newWalletOrder);
|
||||
|
||||
state.tempOrder.forEach(item => {
|
||||
if (item.type === ItemType.WalletSection && !newWalletOrder.some(wallet => wallet.getID() === item.data.getID())) {
|
||||
handleWalletDeletion(item.data.getID());
|
||||
}
|
||||
});
|
||||
|
||||
if (beforeRemoveListenerRef.current) {
|
||||
navigation.removeListener('beforeRemove', beforeRemoveListenerRef.current);
|
||||
}
|
||||
|
@ -251,7 +258,7 @@ const ManageWallets: React.FC = () => {
|
|||
dispatch({ type: SET_SEARCH_QUERY, payload: '' });
|
||||
dispatch({ type: SET_IS_SEARCH_FOCUSED, payload: false });
|
||||
}
|
||||
}, [goBack, setWalletsWithNewOrder, state.searchQuery, state.isSearchFocused, state.tempOrder, navigation]);
|
||||
}, [goBack, setWalletsWithNewOrder, state.searchQuery, state.isSearchFocused, state.tempOrder, navigation, handleWalletDeletion]);
|
||||
|
||||
const hasUnsavedChanges = useMemo(() => {
|
||||
return JSON.stringify(walletsRef.current) !== JSON.stringify(state.tempOrder.map(item => item.data));
|
||||
|
@ -361,15 +368,20 @@ const ManageWallets: React.FC = () => {
|
|||
const presentWalletHasBalanceAlert = useCallback(async (wallet: TWallet) => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
|
||||
try {
|
||||
const balance = formatBalanceWithoutSuffix(wallet.getBalance(), BitcoinUnit.SATS, true);
|
||||
const walletBalanceConfirmation = await prompt(
|
||||
loc.wallets.details_delete_wallet,
|
||||
loc.formatString(loc.wallets.details_del_wb_q, { balance: wallet.getBalance() }),
|
||||
loc.formatString(loc.wallets.details_del_wb_q, { balance }),
|
||||
true,
|
||||
'plain-text',
|
||||
'numeric',
|
||||
true,
|
||||
loc.wallets.details_delete,
|
||||
);
|
||||
if (Number(walletBalanceConfirmation) === wallet.getBalance()) {
|
||||
const cleanedConfirmation = (walletBalanceConfirmation || '').replace(/[^0-9]/g, '');
|
||||
|
||||
if (Number(cleanedConfirmation) === wallet.getBalance()) {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
||||
dispatch({ type: REMOVE_WALLET, payload: wallet.getID() });
|
||||
} else {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
|
@ -381,10 +393,10 @@ const ManageWallets: React.FC = () => {
|
|||
const handleDeleteWallet = useCallback(
|
||||
async (wallet: TWallet) => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
|
||||
Alert.alert(
|
||||
loc.wallets.details_delete_wallet,
|
||||
loc.wallets.details_are_you_sure,
|
||||
[
|
||||
presentAlert({
|
||||
title: loc.wallets.details_delete_wallet,
|
||||
message: loc.wallets.details_are_you_sure,
|
||||
buttons: [
|
||||
{
|
||||
text: loc.wallets.details_yes_delete,
|
||||
onPress: async () => {
|
||||
|
@ -395,7 +407,7 @@ const ManageWallets: React.FC = () => {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (wallet.getBalance() > 0 && wallet.allowSend()) {
|
||||
if (wallet.getBalance && wallet.getBalance() > 0 && wallet.allowSend && wallet.allowSend()) {
|
||||
presentWalletHasBalanceAlert(wallet);
|
||||
} else {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
||||
|
@ -404,10 +416,10 @@ const ManageWallets: React.FC = () => {
|
|||
},
|
||||
style: 'destructive',
|
||||
},
|
||||
{ text: loc.wallets.details_no_cancel, onPress: () => {}, style: 'cancel' },
|
||||
{ text: loc._.cancel, onPress: () => {}, style: 'cancel' },
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
options: { cancelable: false },
|
||||
});
|
||||
},
|
||||
[isBiometricUseCapableAndEnabled, presentWalletHasBalanceAlert],
|
||||
);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
I18nManager,
|
||||
InteractionManager,
|
||||
LayoutAnimation,
|
||||
|
@ -38,18 +37,17 @@ import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
|||
import loc, { formatBalanceWithoutSuffix } from '../../loc';
|
||||
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import { popToTop } from '../../NavigationService';
|
||||
import { useFocusEffect, useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { LightningTransaction, Transaction, TWallet } from '../../class/wallets/types';
|
||||
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
|
||||
import { unsubscribe } from '../../blue_modules/notifications';
|
||||
import HeaderMenuButton from '../../components/HeaderMenuButton';
|
||||
import { Action } from '../../components/types';
|
||||
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
||||
import { popToTop } from '../../NavigationService';
|
||||
|
||||
type RouteProps = RouteProp<DetailViewStackParamList, 'WalletDetails'>;
|
||||
const WalletDetails: React.FC = () => {
|
||||
const { saveToDisk, wallets, deleteWallet, setSelectedWalletID, txMetadata } = useStorage();
|
||||
const { saveToDisk, wallets, setSelectedWalletID, txMetadata, handleWalletDeletion } = useStorage();
|
||||
const { isBiometricUseCapableAndEnabled } = useBiometrics();
|
||||
const { walletID } = useRoute<RouteProps>().params;
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
@ -89,25 +87,11 @@ const WalletDetails: React.FC = () => {
|
|||
}, [wallet]);
|
||||
const [isMasterFingerPrintVisible, setIsMasterFingerPrintVisible] = useState<boolean>(false);
|
||||
|
||||
const navigateToOverviewAndDeleteWallet = useCallback(async () => {
|
||||
const navigateToOverviewAndDeleteWallet = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const externalAddresses = wallet.getAllExternalAddresses();
|
||||
if (externalAddresses.length > 0) {
|
||||
await unsubscribe(externalAddresses, [], []);
|
||||
}
|
||||
deleteWallet(wallet);
|
||||
saveToDisk(true);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||
popToTop();
|
||||
} catch (e: unknown) {
|
||||
console.error(e);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
presentAlert({ message: (e as Error).message });
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [deleteWallet, saveToDisk, wallet]);
|
||||
handleWalletDeletion(wallet.getID());
|
||||
popToTop();
|
||||
}, [handleWalletDeletion, wallet]);
|
||||
|
||||
const presentWalletHasBalanceAlert = useCallback(async () => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
|
||||
|
@ -125,7 +109,7 @@ const WalletDetails: React.FC = () => {
|
|||
const cleanedConfirmation = (walletBalanceConfirmation || '').replace(/[^0-9]/g, '');
|
||||
|
||||
if (Number(cleanedConfirmation) === wallet.getBalance()) {
|
||||
await navigateToOverviewAndDeleteWallet();
|
||||
navigateToOverviewAndDeleteWallet();
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||
} else {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
|
@ -137,10 +121,10 @@ const WalletDetails: React.FC = () => {
|
|||
|
||||
const handleDeleteButtonTapped = useCallback(() => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
|
||||
Alert.alert(
|
||||
loc.wallets.details_delete_wallet,
|
||||
loc.wallets.details_are_you_sure,
|
||||
[
|
||||
presentAlert({
|
||||
title: loc.wallets.details_delete_wallet,
|
||||
message: loc.wallets.details_are_you_sure,
|
||||
buttons: [
|
||||
{
|
||||
text: loc.wallets.details_yes_delete,
|
||||
onPress: async () => {
|
||||
|
@ -159,10 +143,10 @@ const WalletDetails: React.FC = () => {
|
|||
},
|
||||
style: 'destructive',
|
||||
},
|
||||
{ text: loc.wallets.details_no_cancel, onPress: () => {}, style: 'cancel' },
|
||||
{ text: loc._.cancel, onPress: () => {}, style: 'cancel' },
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
options: { cancelable: false },
|
||||
});
|
||||
}, [isBiometricUseCapableAndEnabled, navigateToOverviewAndDeleteWallet, presentWalletHasBalanceAlert, wallet]);
|
||||
|
||||
const exportHistoryContent = useCallback(() => {
|
||||
|
|
Loading…
Add table
Reference in a new issue