Fix one swap tap creating multiple trades (#3709)

TradeIsCreating was only set deep inside createTrade's provider loop,
after several awaits, so the swap button stayed tappable while the
first call was still running and every extra tap started another
trade. createTrade also had no in-progress check of its own.

Now createTrade returns early if a trade is already being created,
sets TradeIsCreating synchronously before the first await, and resets
the state in a finally block so the button is usable again after
success, failure or an unexpected exception. The
ConcurrentModificationError retry now awaits the inner call instead of
re-entering createTrade, so it is not blocked by the new guard.


Claude-Session: https://claude.ai/code/session_016HdqYnWEiqnBvmvqCBQgjE

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
claude[bot]
2026-10-12 13:14:15 +02:00
committed by GitHub
co-authored by Claude
parent 8df61b4a66
commit 09da422470
@@ -1047,6 +1047,27 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
@action
Future<void> 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<void> _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<void>.delayed(Duration(milliseconds: 200));
await _createTrade();
}
}