diff --git a/lib/bloc/coins_bloc/coins_repo.dart b/lib/bloc/coins_bloc/coins_repo.dart index 70d714511f..a928206522 100644 --- a/lib/bloc/coins_bloc/coins_repo.dart +++ b/lib/bloc/coins_bloc/coins_repo.dart @@ -32,6 +32,14 @@ import 'package:web_dex/services/arrr_activation/arrr_activation_service.dart'; import 'package:web_dex/services/fd_monitor_service.dart'; import 'package:web_dex/shared/utils/platform_tuner.dart'; +/// Exception used to indicate that ZHTLC activation was cancelled by the user. +class ZhtlcActivationCancelled implements Exception { + ZhtlcActivationCancelled(this.coinId); + final String coinId; + @override + String toString() => 'ZhtlcActivationCancelled: $coinId'; +} + class CoinsRepo { CoinsRepo({ required KomodoDefiSdk kdfSdk, @@ -933,13 +941,16 @@ class CoinsRepo { // User cancellations have the message "Configuration cancelled by user or timed out" final isUserCancellation = message.contains('cancelled by user'); - if (notifyListeners && !isUserCancellation) { - _broadcastAsset(coin.copyWith(state: CoinState.suspended)); + if (isUserCancellation) { + // Bubble up a typed cancellation so the UI can revert the toggle + throw ZhtlcActivationCancelled(asset.id.id); } - if (!isUserCancellation) { - throw Exception("zcoin activaiton failed: $message"); + if (notifyListeners) { + _broadcastAsset(coin.copyWith(state: CoinState.suspended)); } + + throw Exception('zcoin activaiton failed: $message'); }, needsConfiguration: (coinId, requiredSettings) { _log.severe( diff --git a/lib/bloc/coins_manager/coins_manager_bloc.dart b/lib/bloc/coins_manager/coins_manager_bloc.dart index 9e0d9741fc..e59b5856d1 100644 --- a/lib/bloc/coins_manager/coins_manager_bloc.dart +++ b/lib/bloc/coins_manager/coins_manager_bloc.dart @@ -241,7 +241,17 @@ class CoinsManagerBloc extends Bloc { (state.action == CoinsManagerAction.remove && wasSelected); if (shouldActivate) { - await _tryActivateCoin(coin); + try { + await _tryActivateCoin(coin); + } on ZhtlcActivationCancelled { + // Revert optimistic selection and show a friendly message + selectedCoins.remove(coin); + emit(state.copyWith( + selectedCoins: selectedCoins.toList(), + errorMessage: 'Activation canceled.', + )); + return; + } } else { await _tryDeactivateCoin(coin); } @@ -265,8 +275,12 @@ class CoinsManagerBloc extends Bloc { Future _tryActivateCoin(Coin coin) async { try { await _coinsRepo.activateCoinsSync([coin]); + } on ZhtlcActivationCancelled { + // Rethrow so the caller can revert the optimistic toggle and show UI + rethrow; } catch (e, s) { _log.warning('Failed to activate coin ${coin.abbr}', e, s); + return; } _analyticsBloc.logEvent( AssetEnabledEventData(