Pay Anything Swap Flow (#2503)

* feat: Swap flow for Pay Anything. [WIP] * feat: Pay Anything Swap Flow [WIP] * feat: Pay anything swap flow [WIP] - Add fiat values for send and receive amounts to swap details confirmation bottomsheet * feat: Pay anything swap flow [WIP] - Switch exchangeviewmodel back to factory - Expand address box to fill width * Handle second swipe to swap cta * Add fiat for receive amount * Scope Observers for bottomsheets and add validator * fix: Repeated instances issue for exchangeVM * fix: Estimated fee and balance not correctly updating after wallet switching occurs * fix: Available balance not updating properly after wallet switching * fix: Available balance and fee rate not displaying after wallet is switched in pay anything flow

David Adegoke committed Sep 6, 2025 at 23:31 UTC 198a9a122bd6c65219dfab534837cd29fc9ccc55
2 files changed +29 -13
lib/src/screens/send/widgets/send_card.dart
+7 -1
@@ -3,10 +3,10 @@ import 'dart:async';
3 import 'package:cake_wallet/core/open_crypto_pay/open_cryptopay_service.dart';
4 import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
5 import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart';
6 -import 'package:cake_wallet/src/widgets/bottom_sheet/info_bottom_sheet_widget.dart';
6 import 'package:cake_wallet/src/widgets/bottom_sheet/payment_confirmation_bottom_sheet.dart';
7 import 'package:cake_wallet/src/widgets/bottom_sheet/wallet_switcher_bottom_sheet.dart';
8 import 'package:cake_wallet/src/widgets/bottom_sheet/swap_confirmation_bottom_sheet.dart';
9 +import 'package:cake_wallet/src/widgets/bottom_sheet/info_bottom_sheet_widget.dart';
10 import 'package:cake_wallet/src/widgets/picker.dart';
11 import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
12 import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
@@ -776,6 +776,12 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
776 noteController.text = initialPaymentRequest!.note;
777 }
778
779 + reaction((_) => sendViewModel.isReadyForSend, (bool isReadyForSend) {
780 + if (isReadyForSend) {
781 + sendViewModel.updateSendingBalance();
782 + }
783 + });
784 +
785 _effectsInstalled = true;
786 }
787
lib/view_model/send/output.dart
+22 -12
@@ -118,7 +118,8 @@ abstract class OutputBase with Store {
118 _amount = wownero!.formatterWowneroParseAmount(amount: _cryptoAmount);
119 break;
120 case WalletType.zano:
121 - _amount = zano!.formatterParseAmount(amount: _cryptoAmount, currency: cryptoCurrencyHandler());
121 + _amount = zano!
122 + .formatterParseAmount(amount: _cryptoAmount, currency: cryptoCurrencyHandler());
123 break;
124 case WalletType.none:
125 case WalletType.haven:
@@ -143,6 +144,9 @@ abstract class OutputBase with Store {
144 @computed
145 double get estimatedFee {
146 try {
147 + // forces mobx to rebuild the computed value
148 + final _ = _wallet.syncStatus;
149 +
150 if (_wallet.type == WalletType.tron) {
151 if (cryptoCurrencyHandler() == CryptoCurrency.trx) {
152 final nativeEstimatedFee = tron!.getTronNativeEstimatedFee(_wallet) ?? 0;
@@ -170,7 +174,8 @@ abstract class OutputBase with Store {
174 return bitcoin!.formatterBitcoinAmountToDouble(amount: fee);
175 }
176
173 - if (_wallet.type == WalletType.litecoin || _wallet.type == WalletType.bitcoinCash ||
177 + if (_wallet.type == WalletType.litecoin ||
178 + _wallet.type == WalletType.bitcoinCash ||
179 _wallet.type == WalletType.dogecoin) {
180 return bitcoin!.formatterBitcoinAmountToDouble(amount: fee);
181 }
@@ -192,7 +197,8 @@ abstract class OutputBase with Store {
197 }
198
199 if (_wallet.type == WalletType.zano) {
195 - return zano!.formatterIntAmountToDouble(amount: fee, currency: cryptoCurrencyHandler(), forFee: true);
200 + return zano!.formatterIntAmountToDouble(
201 + amount: fee, currency: cryptoCurrencyHandler(), forFee: true);
202 }
203
204 if (_wallet.type == WalletType.decred) {
@@ -207,6 +213,9 @@ abstract class OutputBase with Store {
213
214 @computed
215 String get estimatedFeeFiatAmount {
216 + // forces mobx to rebuild the computed value
217 + final _ = _wallet.syncStatus;
218 +
219 try {
220 final currency = (isEVMCompatibleChain(_wallet.type) ||
221 _wallet.type == WalletType.solana ||
@@ -235,7 +244,8 @@ abstract class OutputBase with Store {
244 }
245
246 @action
238 - void updateWallet(WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> newWallet) {
247 + void updateWallet(
248 + WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> newWallet) {
249 _wallet = newWallet;
250 _setCryptoNumMaximumFractionDigits();
251 }
@@ -371,15 +381,15 @@ extension OutputCopyWith on Output {
381 );
382
383 clone
374 - ..cryptoAmount = cryptoAmount
384 + ..cryptoAmount = cryptoAmount
385 ..cryptoFullBalance = cryptoFullBalance
376 - ..note = note
377 - ..sendAll = sendAll
378 - ..memo = memo
379 - ..stealthAddress = stealthAddress
380 - ..parsedAddress = parsedAddress ?? this.parsedAddress
381 - ..fiatAmount = fiatAmount ?? this.fiatAmount;
386 + ..note = note
387 + ..sendAll = sendAll
388 + ..memo = memo
389 + ..stealthAddress = stealthAddress
390 + ..parsedAddress = parsedAddress ?? this.parsedAddress
391 + ..fiatAmount = fiatAmount ?? this.fiatAmount;
392
393 return clone;
394 }
385 -}
\ No newline at end of file
395 +}