From f7d29c9f389499e74acebaa5fda392961a805b71 Mon Sep 17 00:00:00 2001 From: Serhii Date: Thu, 9 Oct 2025 15:35:47 +0300 Subject: [PATCH] Cw 1117 prevent sending a transaction twice by mistake (#2567) * Revert "Prevent double send actions in SendPage (#2542)" This reverts commit dd4c941d2f356d7c4f2d39e9744ab43bbe1962c7. * disable send buttons when ExecutedSuccessfully * return value on bottom sheet pop [skip ci] --- lib/cake_pay/src/cards/cake_pay_buy_card_page.dart | 2 +- .../screens/exchange_trade/exchange_trade_page.dart | 12 ++++++++---- lib/src/screens/send/send_page.dart | 13 +------------ .../transaction_details/rbf_details_page.dart | 8 ++++++-- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart b/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart index 68d606014..1d53f9b4b 100644 --- a/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart +++ b/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart @@ -371,7 +371,7 @@ class CakePayBuyCardPage extends BasePage { }, text: S.of(context).purchase_gift_card, isDisabled: !cakePayBuyCardViewModel.isAmountSufficient || - cakePayBuyCardViewModel.isPurchasing, + cakePayBuyCardViewModel.isPurchasing || _sendViewModel.state is ExecutedSuccessfullyState, isLoading: _sendViewModel.state is IsExecutingState || cakePayBuyCardViewModel.isPurchasing, color: Theme.of(context).colorScheme.primary, diff --git a/lib/src/screens/exchange_trade/exchange_trade_page.dart b/lib/src/screens/exchange_trade/exchange_trade_page.dart index 17b6fd71c..1e8e74a2d 100644 --- a/lib/src/screens/exchange_trade/exchange_trade_page.dart +++ b/lib/src/screens/exchange_trade/exchange_trade_page.dart @@ -194,7 +194,8 @@ class ExchangeTradeState extends State { !(sendingState is TransactionCommitted)), child: LoadingPrimaryButton( key: ValueKey('exchange_trade_page_send_from_cake_button_key'), - isDisabled: trade.inputAddress == null || trade.inputAddress!.isEmpty, + isDisabled: trade.inputAddress == null || trade.inputAddress!.isEmpty || + sendingState is ExecutedSuccessfullyState, isLoading: sendingState is IsExecutingState, onPressed: () => widget.exchangeTradeViewModel.confirmSending(), text: S.current.send_from_cake_wallet, @@ -272,9 +273,9 @@ class ExchangeTradeState extends State { } if (state is ExecutedSuccessfullyState) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) async { if (context.mounted) { - showModalBottomSheet( + final result = await showModalBottomSheet( context: context, isDismissible: false, isScrollControlled: true, @@ -304,13 +305,16 @@ class ExchangeTradeState extends State { outputs: widget.exchangeTradeViewModel.sendViewModel.outputs, onSlideActionComplete: () async { if (bottomSheetContext.mounted) { - Navigator.of(bottomSheetContext).pop(); + Navigator.of(bottomSheetContext).pop(true); } widget.exchangeTradeViewModel.sendViewModel.commitTransaction(context); }, ); }, ); + + if (result == null) widget.exchangeTradeViewModel.sendViewModel.dismissTransaction(); + } }); } diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 291541566..f5d180731 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -64,7 +64,6 @@ class SendPage extends BasePage { final PaymentRequest? initialPaymentRequest; bool _effectsInstalled = false; - bool _sendInProgress = false; ContactRecord? newContactAddress; @override @@ -413,9 +412,6 @@ class SendPage extends BasePage { return LoadingPrimaryButton( key: ValueKey('send_page_send_button_key'), onPressed: () async { - // Prevent double taps - if (_sendInProgress) return; - //Request dummy node to get the focus out of the text fields FocusScope.of(context).requestFocus(FocusNode()); @@ -474,8 +470,6 @@ class SendPage extends BasePage { } } - _sendInProgress = true; - final check = sendViewModel.shouldDisplayTotp(); authService.authenticateAction( context, @@ -483,8 +477,6 @@ class SendPage extends BasePage { onAuthSuccess: (value) async { if (value) { await sendViewModel.createTransaction(); - } else { - _sendInProgress = false; } }, ); @@ -496,7 +488,7 @@ class SendPage extends BasePage { sendViewModel.state is TransactionCommitting || sendViewModel.state is IsAwaitingDeviceResponseState || sendViewModel.state is LoadingTemplateExecutingState, - isDisabled: !sendViewModel.isReadyForSend, + isDisabled: !sendViewModel.isReadyForSend || sendViewModel.state is ExecutedSuccessfullyState, ); }, ) @@ -533,7 +525,6 @@ class SendPage extends BasePage { } if (state is FailureState) { - _sendInProgress = false; WidgetsBinding.instance.addPostFrameCallback( (_) { showPopUp( @@ -614,13 +605,11 @@ class SendPage extends BasePage { ); if (result == null) sendViewModel.dismissTransaction(); - _sendInProgress = false; } }); } if (state is TransactionCommitted) { - _sendInProgress = false; WidgetsBinding.instance.addPostFrameCallback((_) async { if (!context.mounted) { return; diff --git a/lib/src/screens/transaction_details/rbf_details_page.dart b/lib/src/screens/transaction_details/rbf_details_page.dart index d83ea5b81..98d267d6a 100644 --- a/lib/src/screens/transaction_details/rbf_details_page.dart +++ b/lib/src/screens/transaction_details/rbf_details_page.dart @@ -105,6 +105,7 @@ class RBFDetailsPage extends BasePage { text: S.of(context).send, isLoading: transactionDetailsViewModel.sendViewModel.state is IsExecutingState, + isDisabled: transactionDetailsViewModel.sendViewModel.state is ExecutedSuccessfullyState, color: Theme.of(context).colorScheme.primary, textColor: Theme.of(context).colorScheme.onPrimary, ))), @@ -180,9 +181,9 @@ class RBFDetailsPage extends BasePage { } if (state is ExecutedSuccessfullyState) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) async { if (context.mounted) { - showModalBottomSheet( + final result = await showModalBottomSheet( context: context, isDismissible: false, isScrollControlled: true, @@ -214,6 +215,9 @@ class RBFDetailsPage extends BasePage { ); }, ); + if (result == null) { + transactionDetailsViewModel.sendViewModel.dismissTransaction(); + } } }); }