diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 0373f5e24..f44dff6d2 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -1047,6 +1047,27 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with @action Future createTrade() async { + // Ignore repeated taps while a trade is already being created + if (tradeState is TradeIsCreating) return; + + // Set synchronously, before the first await, so the swap button shows its + // loading state and further taps are ignored right away + tradeState = TradeIsCreating(); + + try { + await _createTrade(); + } finally { + // Never leave the swap button stuck in its loading state + // (e.g. if an unexpected exception is thrown) + if (tradeState is TradeIsCreating) { + tradeState = TradeIsCreatedFailure( + title: S.current.trade_not_created, + error: S.current.none_of_selected_providers_can_exchange); + } + } + } + + Future _createTrade() async { final depositAmountValue = _depositAmount ?? Money.zero(depositCurrency); final receiveAmountValue = _receiveAmount ?? Money.zero(receiveCurrency); @@ -1335,7 +1356,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with /// /// this is because the limitation of the SplayTreeMap that /// you can't modify it while iterating through it - Future.delayed(Duration(milliseconds: 200), createTrade); + await Future.delayed(Duration(milliseconds: 200)); + await _createTrade(); } }