From 1bd6166f2c9ed485bad411c7fd4d87fe18c0390a Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Mon, 3 Oct 2022 13:18:57 -0600 Subject: [PATCH] use exchange form in wallet initiated exchange flow --- lib/pages/exchange_view/exchange_form.dart | 207 ++- .../wallet_initiated_exchange_view.dart | 1479 +---------------- 2 files changed, 163 insertions(+), 1523 deletions(-) diff --git a/lib/pages/exchange_view/exchange_form.dart b/lib/pages/exchange_view/exchange_form.dart index 644863e1b..b1bb739b6 100644 --- a/lib/pages/exchange_view/exchange_form.dart +++ b/lib/pages/exchange_view/exchange_form.dart @@ -14,6 +14,7 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart'; +import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_provider_options.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/rate_type_toggle.dart'; @@ -26,6 +27,7 @@ import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; @@ -33,15 +35,27 @@ import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:tuple/tuple.dart'; class ExchangeForm extends ConsumerStatefulWidget { - const ExchangeForm({Key? key}) : super(key: key); + const ExchangeForm({ + Key? key, + this.walletId, + this.coin, + }) : super(key: key); + + final String? walletId; + final Coin? coin; @override ConsumerState<ExchangeForm> createState() => _ExchangeFormState(); } class _ExchangeFormState extends ConsumerState<ExchangeForm> { + late final String? walletId; + late final Coin? coin; + late final bool walletInitiated; + late final TextEditingController _sendController; late final TextEditingController _receiveController; final FocusNode _sendFocusNode = FocusNode(); @@ -82,13 +96,21 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { void selectSendCurrency() async { if (ref.read(prefsChangeNotifierProvider).exchangeRateType == ExchangeRateType.estimated) { + final fromTicker = + ref.read(estimatedRateExchangeFormProvider).from?.ticker ?? "-"; + + if (walletInitiated && + fromTicker.toLowerCase() == coin!.ticker.toLowerCase()) { + // do not allow changing away from wallet coin + return; + } + await _showFloatingRateSelectionSheet( currencies: ref.read(availableChangeNowCurrenciesStateProvider.state).state, excludedTicker: ref.read(estimatedRateExchangeFormProvider).to?.ticker ?? "-", - fromTicker: - ref.read(estimatedRateExchangeFormProvider).from?.ticker ?? "-", + fromTicker: fromTicker, onSelected: (from) => ref .read(estimatedRateExchangeFormProvider) .updateFrom(from, true)); @@ -96,6 +118,13 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { final toTicker = ref.read(fixedRateExchangeFormProvider).market?.to ?? ""; final fromTicker = ref.read(fixedRateExchangeFormProvider).market?.from ?? ""; + + if (walletInitiated && + fromTicker.toLowerCase() == coin!.ticker.toLowerCase()) { + // do not allow changing away from wallet coin + return; + } + await _showFixedRateSelectionSheet( excludedTicker: toTicker, fromTicker: fromTicker, @@ -129,6 +158,15 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { void selectReceiveCurrency() async { if (ref.read(prefsChangeNotifierProvider).exchangeRateType == ExchangeRateType.estimated) { + final toTicker = + ref.read(estimatedRateExchangeFormProvider).to?.ticker ?? ""; + + if (walletInitiated && + toTicker.toLowerCase() == coin!.ticker.toLowerCase()) { + // do not allow changing away from wallet coin + return; + } + await _showFloatingRateSelectionSheet( currencies: ref.read(availableChangeNowCurrenciesStateProvider.state).state, @@ -141,6 +179,14 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { } else { final fromTicker = ref.read(fixedRateExchangeFormProvider).market?.from ?? ""; + final toTicker = ref.read(fixedRateExchangeFormProvider).market?.to ?? ""; + + if (walletInitiated && + toTicker.toLowerCase() == coin!.ticker.toLowerCase()) { + // do not allow changing away from wallet coin + return; + } + await _showFixedRateSelectionSheet( excludedTicker: fromTicker, fromTicker: fromTicker, @@ -173,9 +219,11 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { void receiveFieldOnChanged(String value) async { final newToAmount = Decimal.tryParse(value); + final isEstimated = + ref.read(prefsChangeNotifierProvider).exchangeRateType == + ExchangeRateType.estimated; if (newToAmount != null) { - if (ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated) { + if (isEstimated) { // await ref // .read(estimatedRateExchangeFormProvider) // .setToAmountAndCalculateFromAmount( @@ -186,8 +234,7 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { .setToAmountAndCalculateFromAmount(newToAmount, false); } } else { - if (ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated) { + if (isEstimated) { // await ref // .read(estimatedRateExchangeFormProvider) // .setToAmountAndCalculateFromAmount( @@ -547,11 +594,20 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { ); if (mounted) { - ref.read(exchangeSendFromWalletIdStateProvider.state).state = null; - unawaited(Navigator.of(context).pushNamed( - Step1View.routeName, - arguments: model, - )); + if (walletInitiated) { + ref.read(exchangeSendFromWalletIdStateProvider.state).state = + Tuple2(walletId!, coin!); + unawaited(Navigator.of(context).pushNamed( + Step2View.routeName, + arguments: model, + )); + } else { + ref.read(exchangeSendFromWalletIdStateProvider.state).state = null; + unawaited(Navigator.of(context).pushNamed( + Step1View.routeName, + arguments: model, + )); + } } } else { final fromTicker = @@ -640,29 +696,80 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { ); if (mounted) { - ref.read(exchangeSendFromWalletIdStateProvider.state).state = null; - unawaited(Navigator.of(context).pushNamed( - Step1View.routeName, - arguments: model, - )); + if (walletInitiated) { + ref.read(exchangeSendFromWalletIdStateProvider.state).state = + Tuple2(walletId!, coin!); + unawaited(Navigator.of(context).pushNamed( + Step2View.routeName, + arguments: model, + )); + } else { + ref.read(exchangeSendFromWalletIdStateProvider.state).state = null; + unawaited(Navigator.of(context).pushNamed( + Step1View.routeName, + arguments: model, + )); + } } } } + bool isWalletCoin(Coin? coin, bool isSend) { + if (coin == null) { + return false; + } + + String? ticker; + + if (ref.read(prefsChangeNotifierProvider).exchangeRateType == + ExchangeRateType.estimated) { + if (isSend) { + ticker = ref.watch(estimatedRateExchangeFormProvider + .select((value) => value.from?.ticker)); + } else { + ticker = ref.watch(estimatedRateExchangeFormProvider + .select((value) => value.to?.ticker)); + } + } else { + if (isSend) { + ticker = ref.read(fixedRateExchangeFormProvider).market?.from; + } else { + ticker = ref.read(fixedRateExchangeFormProvider).market?.to; + } + } + + if (ticker == null) { + return false; + } + + return coin.ticker.toUpperCase() == ticker.toUpperCase(); + } + @override void initState() { _sendController = TextEditingController(); _receiveController = TextEditingController(); - final isEstimated = - ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated; - _sendController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).fromAmountString - : ref.read(fixedRateExchangeFormProvider).fromAmountString; - _receiveController.text = isEstimated - ? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString - : ref.read(fixedRateExchangeFormProvider).toAmountString; + walletId = widget.walletId; + coin = widget.coin; + walletInitiated = walletId != null && coin != null; + + if (walletInitiated) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + ref.read(estimatedRateExchangeFormProvider).clearAmounts(true); + // ref.read(fixedRateExchangeFormProvider); + }); + } else { + final isEstimated = + ref.read(prefsChangeNotifierProvider).exchangeRateType == + ExchangeRateType.estimated; + _sendController.text = isEstimated + ? ref.read(estimatedRateExchangeFormProvider).fromAmountString + : ref.read(fixedRateExchangeFormProvider).fromAmountString; + _receiveController.text = isEstimated + ? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString + : ref.read(fixedRateExchangeFormProvider).toAmountString; + } _sendFocusNode.addListener(() async { if (!_sendFocusNode.hasFocus) { @@ -930,17 +1037,19 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { .textDark, ), ), - const SizedBox( - width: 6, - ), - SvgPicture.asset( - Assets.svg.chevronDown, - width: 5, - height: 2.5, - color: Theme.of(context) - .extension<StackColors>()! - .textDark, - ), + if (!isWalletCoin(coin, true)) + const SizedBox( + width: 6, + ), + if (!isWalletCoin(coin, true)) + SvgPicture.asset( + Assets.svg.chevronDown, + width: 5, + height: 2.5, + color: Theme.of(context) + .extension<StackColors>()! + .textDark, + ), ], ), ), @@ -1148,17 +1257,19 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { .textDark, ), ), - const SizedBox( - width: 6, - ), - SvgPicture.asset( - Assets.svg.chevronDown, - width: 5, - height: 2.5, - color: Theme.of(context) - .extension<StackColors>()! - .textDark, - ), + if (!isWalletCoin(coin, false)) + const SizedBox( + width: 6, + ), + if (!isWalletCoin(coin, false)) + SvgPicture.asset( + Assets.svg.chevronDown, + width: 5, + height: 2.5, + color: Theme.of(context) + .extension<StackColors>()! + .textDark, + ), ], ), ), diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index cfd967bd0..c816d4fe8 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -1,39 +1,13 @@ import 'dart:async'; -import 'package:decimal/decimal.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; -import 'package:stackwallet/models/exchange/response_objects/currency.dart'; -import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart'; -import 'package:stackwallet/models/exchange/response_objects/pair.dart'; -import 'package:stackwallet/notifications/show_flush_bar.dart'; -import 'package:stackwallet/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart'; -import 'package:stackwallet/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart'; -import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; -import 'package:stackwallet/pages/exchange_view/exchange_view.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; +import 'package:stackwallet/pages/exchange_view/exchange_form.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; -import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart'; -import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart'; -import 'package:stackwallet/providers/exchange/change_now_provider.dart'; -import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart'; -import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart'; -import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart'; -import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart'; -import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; -import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; -import 'package:stackwallet/widgets/custom_loading_overlay.dart'; -import 'package:stackwallet/widgets/loading_indicator.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; -import 'package:tuple/tuple.dart'; class WalletInitiatedExchangeView extends ConsumerStatefulWidget { const WalletInitiatedExchangeView({ @@ -57,260 +31,15 @@ class _WalletInitiatedExchangeViewState late final String walletId; late final Coin coin; - late final TextEditingController _sendController; - late final TextEditingController _receiveController; - - final FocusNode _sendFocusNode = FocusNode(); - final FocusNode _receiveFocusNode = FocusNode(); - - bool _swapLock = false; - - Future<void> _swap() async { - _swapLock = true; - _sendFocusNode.unfocus(); - _receiveFocusNode.unfocus(); - - unawaited( - showDialog<void>( - context: context, - barrierDismissible: false, - builder: (_) => WillPopScope( - onWillPop: () async => false, - child: Container( - color: Theme.of(context) - .extension<StackColors>()! - .overlay - .withOpacity(0.6), - child: const CustomLoadingOverlay( - message: "Updating exchange rate", - eventBus: null, - ), - ), - ), - ), - ); - - if (ref.watch(prefsChangeNotifierProvider - .select((pref) => pref.exchangeRateType)) == - ExchangeRateType.estimated) { - await ref.read(estimatedRateExchangeFormProvider).swap(); - } else { - final from = ref.read(fixedRateExchangeFormProvider).market?.from; - final to = ref.read(fixedRateExchangeFormProvider).market?.to; - - if (to != null && from != null) { - final markets = ref - .read(fixedRateMarketPairsStateProvider.state) - .state - .where((e) => e.from == to && e.to == from); - - if (markets.isNotEmpty) { - await ref.read(fixedRateExchangeFormProvider).swap(markets.first); - } - } - } - if (mounted) { - Navigator.of(context).pop(); - } - _swapLock = false; - } - - Future<void> _showFloatingRateSelectionSheet({ - required List<Currency> currencies, - required String excludedTicker, - required String fromTicker, - required void Function(Currency) onSelected, - }) async { - _sendFocusNode.unfocus(); - _receiveFocusNode.unfocus(); - - List<Pair> availablePairs = []; - if (fromTicker.isEmpty || - fromTicker == "-" || - excludedTicker.isEmpty || - excludedTicker == "-") { - availablePairs = - ref.read(availableFloatingRatePairsStateProvider.state).state; - } else if (excludedTicker == fromTicker) { - availablePairs = ref - .read(availableFloatingRatePairsStateProvider.state) - .state - .where((e) => e.from == excludedTicker) - .toList(growable: false); - } else { - availablePairs = ref - .read(availableFloatingRatePairsStateProvider.state) - .state - .where((e) => e.to == excludedTicker) - .toList(growable: false); - } - - final List<Currency> tickers = currencies.where((e) { - if (excludedTicker == fromTicker) { - return e.ticker != excludedTicker && - availablePairs.where((e2) => e2.to == e.ticker).isNotEmpty; - } else { - return e.ticker != excludedTicker && - availablePairs.where((e2) => e2.from == e.ticker).isNotEmpty; - } - }).toList(growable: false); - - final result = await Navigator.of(context).push( - MaterialPageRoute<dynamic>( - builder: (_) => FloatingRateCurrencySelectionView( - currencies: tickers, - ), - ), - ); - - if (mounted && result is Currency) { - onSelected(result); - } - } - - String? _fetchIconUrlFromTickerForFixedRateFlow(String? ticker) { - if (ticker == null) return null; - - final possibleCurrencies = ref - .read(availableChangeNowCurrenciesStateProvider.state) - .state - .where((e) => e.ticker.toUpperCase() == ticker.toUpperCase()); - - for (final currency in possibleCurrencies) { - if (currency.image.isNotEmpty) { - return currency.image; - } - } - - return null; - } - - Future<void> _showFixedRateSelectionSheet({ - required String excludedTicker, - required String fromTicker, - required void Function(String) onSelected, - }) async { - _sendFocusNode.unfocus(); - _receiveFocusNode.unfocus(); - - List<FixedRateMarket> marketsThatPairWithExcludedTicker = []; - - if (excludedTicker == "" || - excludedTicker == "-" || - fromTicker == "" || - fromTicker == "-") { - marketsThatPairWithExcludedTicker = - ref.read(fixedRateMarketPairsStateProvider.state).state; - } else if (excludedTicker == fromTicker) { - marketsThatPairWithExcludedTicker = ref - .read(fixedRateMarketPairsStateProvider.state) - .state - .where((e) => e.from == excludedTicker && e.to != excludedTicker) - .toList(growable: false); - } else { - marketsThatPairWithExcludedTicker = ref - .read(fixedRateMarketPairsStateProvider.state) - .state - .where((e) => e.to == excludedTicker && e.from != excludedTicker) - .toList(growable: false); - } - - final result = await Navigator.of(context).push( - MaterialPageRoute<dynamic>( - builder: (_) => FixedRateMarketPairCoinSelectionView( - markets: marketsThatPairWithExcludedTicker, - currencies: - ref.read(availableChangeNowCurrenciesStateProvider.state).state, - isFrom: excludedTicker != fromTicker, - ), - ), - ); - - if (mounted && result is String) { - onSelected(result); - } - } - @override void initState() { walletId = widget.walletId; coin = widget.coin; - _sendController = TextEditingController(); - _receiveController = TextEditingController(); - - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - ref.read(estimatedRateExchangeFormProvider).clearAmounts(true); - // ref.read(fixedRateExchangeFormProvider); - }); - _sendFocusNode.addListener(() async { - if (!_sendFocusNode.hasFocus) { - final newFromAmount = Decimal.tryParse(_sendController.text); - if (newFromAmount != null) { - if (ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated) { - await ref - .read(estimatedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount(newFromAmount, true); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount(newFromAmount, true); - } - } else { - if (ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated) { - await ref - .read(estimatedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount(Decimal.zero, true); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount(Decimal.zero, true); - } - _receiveController.text = - ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated - ? "-" - : ""; - } - } - }); - _receiveFocusNode.addListener(() async { - if (!_receiveFocusNode.hasFocus) { - final newToAmount = Decimal.tryParse(_receiveController.text); - if (newToAmount != null) { - if (ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated) { - // await ref - // .read(estimatedRateExchangeFormProvider) - // .setToAmountAndCalculateFromAmount(newToAmount, true); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setToAmountAndCalculateFromAmount(newToAmount, true); - } - } else { - if (ref.read(prefsChangeNotifierProvider).exchangeRateType == - ExchangeRateType.estimated) { - // await ref - // .read(estimatedRateExchangeFormProvider) - // .setToAmountAndCalculateFromAmount(Decimal.zero, true); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setToAmountAndCalculateFromAmount(Decimal.zero, true); - } - _sendController.text = ""; - } - } - }); super.initState(); } @override void dispose() { - _receiveController.dispose(); - _sendController.dispose(); super.dispose(); } @@ -318,48 +47,6 @@ class _WalletInitiatedExchangeViewState Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - final isEstimated = ref.watch(prefsChangeNotifierProvider - .select((pref) => pref.exchangeRateType)) == - ExchangeRateType.estimated; - - ref.listen( - isEstimated - ? estimatedRateExchangeFormProvider - .select((value) => value.toAmountString) - : fixedRateExchangeFormProvider.select( - (value) => value.toAmountString), (previous, String next) { - if (!_receiveFocusNode.hasFocus) { - _receiveController.text = isEstimated && next.isEmpty ? "-" : next; - debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED"); - if (_swapLock) { - _sendController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).fromAmountString - : ref.read(fixedRateExchangeFormProvider).fromAmountString; - } - } - }); - ref.listen( - isEstimated - ? estimatedRateExchangeFormProvider - .select((value) => value.fromAmountString) - : fixedRateExchangeFormProvider.select( - (value) => value.fromAmountString), (previous, String next) { - if (!_sendFocusNode.hasFocus) { - _sendController.text = next; - debugPrint("SEND AMOUNT LISTENER ACTIVATED"); - if (_swapLock) { - _receiveController.text = isEstimated - ? ref - .read(estimatedRateExchangeFormProvider) - .toAmountString - .isEmpty - ? "-" - : ref.read(estimatedRateExchangeFormProvider).toAmountString - : ref.read(fixedRateExchangeFormProvider).toAmountString; - } - } - }); - return Scaffold( backgroundColor: Theme.of(context).extension<StackColors>()!.background, appBar: AppBar( @@ -417,1167 +104,9 @@ class _WalletInitiatedExchangeViewState const SizedBox( height: 24, ), - Text( - "You will send", - style: STextStyles.itemSubtitle(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .textDark3, - ), - ), - const SizedBox( - height: 4, - ), - TextFormField( - style: STextStyles.smallMed14(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .textDark, - ), - focusNode: _sendFocusNode, - controller: _sendController, - textAlign: TextAlign.right, - onTap: () { - if (_sendController.text == "-") { - _sendController.text = ""; - } - }, - onChanged: (value) async { - final newFromAmount = Decimal.tryParse(value); - if (newFromAmount != null) { - if (ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) { - await ref - .read(estimatedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount( - newFromAmount, false); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount( - newFromAmount, false); - } - } else { - if (ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) { - await ref - .read(estimatedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount( - Decimal.zero, false); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount( - Decimal.zero, false); - } - _receiveController.text = isEstimated ? "-" : ""; - } - }, - keyboardType: const TextInputType.numberWithOptions( - signed: false, - decimal: true, - ), - inputFormatters: [ - // regex to validate a crypto amount with 8 decimal places - TextInputFormatter.withFunction((oldValue, - newValue) => - RegExp(r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$') - .hasMatch(newValue.text) - ? newValue - : oldValue), - ], - decoration: InputDecoration( - contentPadding: const EdgeInsets.only( - top: 12, - right: 12, - ), - hintText: "0", - hintStyle: STextStyles.fieldLabel(context).copyWith( - fontSize: 14, - ), - prefixIcon: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: GestureDetector( - onTap: () async { - if (ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) { - final String fromTicker = ref - .read( - estimatedRateExchangeFormProvider) - .from - ?.ticker ?? - "-"; - - if (fromTicker.toLowerCase() == - coin.ticker.toLowerCase()) { - // do not allow changing away from wallet coin - return; - } - - await _showFloatingRateSelectionSheet( - currencies: ref - .read( - availableChangeNowCurrenciesStateProvider - .state) - .state, - excludedTicker: ref - .read( - estimatedRateExchangeFormProvider) - .to - ?.ticker ?? - "-", - fromTicker: fromTicker, - onSelected: (from) => ref - .read( - estimatedRateExchangeFormProvider) - .updateFrom(from, true)); - } else { - final toTicker = ref - .read(fixedRateExchangeFormProvider) - .market - ?.to ?? - ""; - final fromTicker = ref - .read(fixedRateExchangeFormProvider) - .market - ?.from ?? - ""; - - if (fromTicker.toLowerCase() == - coin.ticker.toLowerCase()) { - // do not allow changing away from wallet coin - return; - } - await _showFixedRateSelectionSheet( - excludedTicker: toTicker, - fromTicker: fromTicker, - onSelected: (selectedFromTicker) async { - try { - final market = ref - .read( - fixedRateMarketPairsStateProvider - .state) - .state - .firstWhere( - (e) => - e.to == toTicker && - e.from == - selectedFromTicker, - ); - - await ref - .read( - fixedRateExchangeFormProvider) - .updateMarket(market, true); - } catch (e) { - unawaited(showDialog<dynamic>( - context: context, - builder: (_) => const StackDialog( - title: "Fixed rate market error", - message: - "Could not find the specified fixed rate trade pair", - ), - )); - return; - } - }, - ); - } - }, - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.all(12), - child: Row( - children: [ - Container( - width: 18, - height: 18, - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(18), - ), - child: Builder( - builder: (context) { - String? image; - if (ref.watch(prefsChangeNotifierProvider - .select((value) => value - .exchangeRateType)) == - ExchangeRateType.estimated) { - image = ref - .watch( - estimatedRateExchangeFormProvider - .select((value) => - value.from)) - ?.image; - } else { - image = _fetchIconUrlFromTickerForFixedRateFlow( - ref.watch( - fixedRateExchangeFormProvider - .select((value) => - value.market - ?.from))); - } - if (image != null && - image.isNotEmpty) { - return Center( - child: SvgPicture.network( - image, - height: 18, - placeholderBuilder: (_) => - Container( - width: 18, - height: 18, - decoration: BoxDecoration( - color: Theme.of(context) - .extension< - StackColors>()! - .textSubtitle2, - borderRadius: - BorderRadius - .circular( - 18, - ), - ), - child: ClipRRect( - borderRadius: - BorderRadius - .circular( - 18, - ), - child: - const LoadingIndicator(), - ), - ), - ), - ); - } else { - return Container( - width: 18, - height: 18, - decoration: BoxDecoration( - // color: Theme.of(context).extension<StackColors>()!.accentColorDark - borderRadius: - BorderRadius.circular( - 18), - ), - child: SvgPicture.asset( - Assets.svg.circleQuestion, - width: 18, - height: 18, - color: Theme.of(context) - .extension< - StackColors>()! - .textSubtitle2, - ), - ); - } - }, - ), - ), - const SizedBox( - width: 6, - ), - Text( - isEstimated - ? ref.watch( - estimatedRateExchangeFormProvider - .select((value) => value - .from?.ticker - .toUpperCase())) ?? - "-" - : ref.watch( - fixedRateExchangeFormProvider - .select((value) => value - .market?.from - .toUpperCase())) ?? - "-", - style: STextStyles.smallMed14(context) - .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), - ), - const SizedBox( - width: 6, - ), - Builder(builder: (context) { - final ticker = isEstimated - ? ref.watch( - estimatedRateExchangeFormProvider - .select((value) => - value.from - ?.ticker)) ?? - "-" - : ref.watch( - fixedRateExchangeFormProvider - .select((value) => - value.market - ?.from)) ?? - "-"; - if (ticker.toLowerCase() == - coin.ticker.toLowerCase()) { - return Container(); - } - return SvgPicture.asset( - Assets.svg.chevronDown, - width: 5, - height: 2.5, - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark); - }), - ], - ), - ), - ), - ), - ), - ), - ), - const SizedBox( - height: 4, - ), - Stack( - children: [ - Positioned.fill( - child: Align( - alignment: Alignment.bottomLeft, - child: Text( - "You will receive", - style: STextStyles.itemSubtitle(context) - .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .textDark3, - ), - ), - ), - ), - Center( - child: GestureDetector( - onTap: () async { - await _swap(); - }, - child: Padding( - padding: const EdgeInsets.all(4), - child: SvgPicture.asset( - Assets.svg.swap, - width: 20, - height: 20, - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark, - ), - ), - ), - ), - Positioned.fill( - child: Align( - alignment: Alignment.topRight, - child: Text( - isEstimated - ? ref.watch( - estimatedRateExchangeFormProvider - .select((value) => - value.minimumSendWarning)) - : ref.watch(fixedRateExchangeFormProvider - .select((value) => - value.sendAmountWarning)), - style: STextStyles.errorSmall(context), - ), - ), - ), - ], - ), - const SizedBox( - height: 4, - ), - TextFormField( - style: STextStyles.smallMed14(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .textDark, - ), - focusNode: _receiveFocusNode, - controller: _receiveController, - readOnly: ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated, - onTap: () { - if (!isEstimated && - _receiveController.text == "-") { - _receiveController.text = ""; - } - }, - onChanged: (value) async { - final newToAmount = Decimal.tryParse(value); - if (newToAmount != null) { - if (ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) { - // await ref - // .read(estimatedRateExchangeFormProvider) - // .setToAmountAndCalculateFromAmount( - // newToAmount, false); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setToAmountAndCalculateFromAmount( - newToAmount, false); - } - } else { - if (ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) { - // await ref - // .read(estimatedRateExchangeFormProvider) - // .setToAmountAndCalculateFromAmount( - // Decimal.zero, false); - } else { - await ref - .read(fixedRateExchangeFormProvider) - .setToAmountAndCalculateFromAmount( - Decimal.zero, false); - } - _sendController.text = ""; - } - }, - textAlign: TextAlign.right, - keyboardType: const TextInputType.numberWithOptions( - signed: false, - decimal: true, - ), - inputFormatters: [ - // regex to validate a crypto amount with 8 decimal places - TextInputFormatter.withFunction((oldValue, - newValue) => - RegExp(r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$') - .hasMatch(newValue.text) - ? newValue - : oldValue), - ], - decoration: InputDecoration( - contentPadding: const EdgeInsets.only( - top: 12, - right: 12, - ), - hintText: "0", - hintStyle: STextStyles.fieldLabel(context).copyWith( - fontSize: 14, - ), - prefixIcon: FittedBox( - fit: BoxFit.scaleDown, - child: GestureDetector( - onTap: () async { - if (ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) { - final toTicker = ref - .read( - estimatedRateExchangeFormProvider) - .to - ?.ticker ?? - ""; - - if (toTicker.toLowerCase() == - coin.ticker.toLowerCase()) { - // do not allow changing away from wallet coin - return; - } - - await _showFloatingRateSelectionSheet( - currencies: ref - .read( - availableChangeNowCurrenciesStateProvider - .state) - .state, - excludedTicker: ref - .read( - estimatedRateExchangeFormProvider) - .from - ?.ticker ?? - "", - fromTicker: ref - .read( - estimatedRateExchangeFormProvider) - .from - ?.ticker ?? - "", - onSelected: (to) => ref - .read( - estimatedRateExchangeFormProvider) - .updateTo(to, true)); - } else { - final fromTicker = ref - .read(fixedRateExchangeFormProvider) - .market - ?.from ?? - ""; - final toTicker = ref - .read(fixedRateExchangeFormProvider) - .market - ?.to ?? - ""; - if (toTicker.toLowerCase() == - coin.ticker.toLowerCase()) { - // do not allow changing away from wallet coin - return; - } - await _showFixedRateSelectionSheet( - excludedTicker: fromTicker, - fromTicker: fromTicker, - onSelected: (selectedToTicker) async { - try { - final market = ref - .read( - fixedRateMarketPairsStateProvider - .state) - .state - .firstWhere( - (e) => - e.to == selectedToTicker && - e.from == fromTicker, - ); - - await ref - .read( - fixedRateExchangeFormProvider) - .updateMarket(market, true); - } catch (e) { - unawaited(showDialog<dynamic>( - context: context, - builder: (_) => const StackDialog( - title: "Fixed rate market error", - message: - "Could not find the specified fixed rate trade pair", - ), - )); - return; - } - }, - ); - } - }, - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.all(12), - child: Row( - children: [ - Container( - width: 18, - height: 18, - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(18), - ), - child: Builder( - builder: (context) { - String? image; - if (ref.watch(prefsChangeNotifierProvider - .select((value) => value - .exchangeRateType)) == - ExchangeRateType.estimated) { - image = ref - .watch( - estimatedRateExchangeFormProvider - .select((value) => - value.to)) - ?.image; - } else { - image = _fetchIconUrlFromTickerForFixedRateFlow( - ref.watch( - fixedRateExchangeFormProvider - .select((value) => - value.market - ?.to))); - } - if (image != null && - image.isNotEmpty) { - return Center( - child: SvgPicture.network( - image, - height: 18, - placeholderBuilder: (_) => - Container( - width: 18, - height: 18, - decoration: BoxDecoration( - color: Theme.of(context) - .extension< - StackColors>()! - .textSubtitle2, - borderRadius: - BorderRadius - .circular(18), - ), - child: ClipRRect( - borderRadius: - BorderRadius - .circular( - 18, - ), - child: - const LoadingIndicator(), - ), - ), - ), - ); - } else { - return Container( - width: 18, - height: 18, - decoration: BoxDecoration( - // color: Theme.of(context).extension<StackColors>()!.accentColorDark - borderRadius: - BorderRadius.circular( - 18), - ), - child: SvgPicture.asset( - Assets.svg.circleQuestion, - width: 18, - height: 18, - color: Theme.of(context) - .extension< - StackColors>()! - .textSubtitle2, - ), - ); - } - }, - ), - ), - const SizedBox( - width: 6, - ), - Text( - isEstimated - ? ref.watch( - estimatedRateExchangeFormProvider - .select((value) => value - .to?.ticker - .toUpperCase())) ?? - "-" - : ref.watch( - fixedRateExchangeFormProvider - .select((value) => value - .market?.to - .toUpperCase())) ?? - "-", - style: STextStyles.smallMed14(context) - .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), - ), - const SizedBox( - width: 6, - ), - Builder(builder: (context) { - final ticker = isEstimated - ? ref.watch( - estimatedRateExchangeFormProvider - .select((value) => - value.to - ?.ticker)) ?? - "-" - : ref.watch( - fixedRateExchangeFormProvider - .select((value) => - value.market - ?.to)) ?? - "-"; - if (ticker.toLowerCase() == - coin.ticker.toLowerCase()) { - return Container(); - } - return SvgPicture.asset( - Assets.svg.chevronDown, - width: 5, - height: 2.5, - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark); - }), - ], - ), - ), - ), - ), - ), - ), - ), - // if (ref - // .watch(exchangeFormSateProvider - // .select((value) => value.minimumReceiveWarning)) - // .isNotEmpty) - // SizedBox( - // height: 4, - // ), - // - // if (ref - // .watch(exchangeFormSateProvider - // .select((value) => value.minimumReceiveWarning)) - // .isNotEmpty) - // Row( - // children: [ - // Spacer(), - // Text( - // ref.watch(exchangeFormSateProvider.select( - // (value) => value.minimumReceiveWarning)), - // style: STextStyles.errorSmall(context), - // ), - // ], - // ), - - const SizedBox( - height: 12, - ), - RateInfo( - onChanged: (rateType) async { - _receiveFocusNode.unfocus(); - _sendFocusNode.unfocus(); - switch (rateType) { - case ExchangeRateType.estimated: - final market = ref - .read(fixedRateExchangeFormProvider) - .market; - final fromTicker = market?.from ?? ""; - final toTicker = market?.to ?? ""; - if (!(fromTicker.isEmpty || - toTicker.isEmpty || - toTicker == "-" || - fromTicker == "-")) { - final available = ref - .read( - availableFloatingRatePairsStateProvider - .state) - .state - .where((e) => - e.to == toTicker && - e.from == fromTicker); - if (available.isNotEmpty) { - final availableCurrencies = ref - .read( - availableChangeNowCurrenciesStateProvider - .state) - .state - .where((e) => - e.ticker == fromTicker || - e.ticker == toTicker); - if (availableCurrencies.length > 1) { - final from = - availableCurrencies.firstWhere( - (e) => e.ticker == fromTicker); - final to = availableCurrencies.firstWhere( - (e) => e.ticker == toTicker); - - await ref - .read( - estimatedRateExchangeFormProvider) - .updateTo(to, false); - await ref - .read( - estimatedRateExchangeFormProvider) - .updateFrom(from, true); - return; - } - } - } - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: - "Estimated rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last estimated rate pair.", - context: context, - )); - break; - case ExchangeRateType.fixed: - final fromTicker = ref - .read(estimatedRateExchangeFormProvider) - .from - ?.ticker ?? - ""; - final toTicker = ref - .read(estimatedRateExchangeFormProvider) - .to - ?.ticker ?? - ""; - if (!(fromTicker.isEmpty || - toTicker.isEmpty || - toTicker == "-" || - fromTicker == "-")) { - FixedRateMarket? market; - try { - market = ref - .read(fixedRateMarketPairsStateProvider - .state) - .state - .firstWhere((e) => - e.from == fromTicker && - e.to == toTicker); - } catch (_) { - market = null; - } - await ref - .read(fixedRateExchangeFormProvider) - .updateMarket(market, true); - await ref - .read(fixedRateExchangeFormProvider) - .setFromAmountAndCalculateToAmount( - Decimal.tryParse( - _sendController.text) ?? - Decimal.zero, - true, - ); - return; - } - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: - "Fixed rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last fixed rate pair.", - context: context, - )); - break; - } - }, - ), - const SizedBox( - height: 12, - ), - const Spacer(), - TextButton( - style: ((ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) - ? ref.watch(estimatedRateExchangeFormProvider - .select((value) => value.canExchange)) - : ref.watch(fixedRateExchangeFormProvider - .select((value) => value.canExchange))) - ? Theme.of(context) - .extension<StackColors>()! - .getPrimaryEnabledButtonColor(context) - : Theme.of(context) - .extension<StackColors>()! - .getSecondaryEnabledButtonColor(context), - onPressed: ((ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) - ? ref.watch(estimatedRateExchangeFormProvider - .select((value) => value.canExchange)) - : ref.watch(fixedRateExchangeFormProvider - .select((value) => value.canExchange))) - ? () async { - final isEstimated = ref - .read(prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated; - - // final ft = isEstimated - // ? ref - // .read( - // estimatedRateExchangeFormProvider) - // .from - // ?.ticker ?? - // "" - // : ref - // .read( - // fixedRateExchangeFormProvider) - // .market - // ?.from ?? - // ""; - // - // final manager = ref - // .read(walletsChangeNotifierProvider) - // .getManager(walletId); - final sendAmount = Decimal.parse(ref - .read(estimatedRateExchangeFormProvider) - .fromAmountString); - - // if (ft.toLowerCase() == - // coin.ticker.toLowerCase()) { - // bool shouldPop = false; - // bool wasPopped = false; - // unawaited(showDialog<void>( - // context: context, - // builder: (_) => WillPopScope( - // onWillPop: () async { - // if (shouldPop) { - // wasPopped = true; - // } - // return shouldPop; - // }, - // child: const CustomLoadingOverlay( - // message: "Checking available balance", - // eventBus: null, - // ), - // ), - // )); - // - // final availableBalance = - // await manager.availableBalance; - // - // final feeObject = await manager.fees; - // - // final fee = await manager.estimateFeeFor( - // Format.decimalAmountToSatoshis( - // sendAmount), - // feeObject.medium); - // - // shouldPop = true; - // if (!wasPopped && mounted) { - // Navigator.of(context).pop(); - // } - // - // if (availableBalance < - // sendAmount + - // Format.satoshisToAmount(fee)) { - // unawaited(showDialog<void>( - // context: context, - // builder: (_) => StackOkDialog( - // title: "Insufficient balance", - // message: - // "Current ${coin.prettyName} wallet does not have enough ${coin.ticker} for this trade", - // ), - // )); - // return; - // } - // } - - if (isEstimated) { - final fromTicker = ref - .read( - estimatedRateExchangeFormProvider) - .from - ?.ticker ?? - ""; - final toTicker = ref - .read( - estimatedRateExchangeFormProvider) - .to - ?.ticker ?? - ""; - - bool isAvailable = false; - final availableFloatingPairs = ref - .read( - availableFloatingRatePairsStateProvider - .state) - .state; - for (final pair in availableFloatingPairs) { - if (pair.from == fromTicker && - pair.to == toTicker) { - isAvailable = true; - break; - } - } - - if (!isAvailable) { - unawaited(showDialog<dynamic>( - context: context, - barrierDismissible: true, - builder: (_) => StackDialog( - title: - "Selected trade pair unavailable", - message: - "The $fromTicker - $toTicker market is currently disabled for estimated/floating rate trades", - ), - )); - return; - } - - final rateType = ref - .read(prefsChangeNotifierProvider) - .exchangeRateType; - - final response = await ref - .read(changeNowProvider) - .getEstimate( - fromTicker, - toTicker, - sendAmount, - false, - false, - ); - - if (response.value == null) { - unawaited(showDialog<dynamic>( - context: context, - barrierDismissible: true, - builder: (_) => StackDialog( - title: - "Failed to update trade estimate", - message: - response.exception?.toString(), - ), - )); - return; - } - - String rate = - "1 ${fromTicker.toUpperCase()} ~${(response.value!.estimatedAmount / sendAmount).toDecimal(scaleOnInfinitePrecision: 8).toStringAsFixed(8)} ${toTicker.toUpperCase()}"; - - final model = IncompleteExchangeModel( - sendTicker: fromTicker.toUpperCase(), - receiveTicker: toTicker.toUpperCase(), - rateInfo: rate, - sendAmount: sendAmount, - receiveAmount: - response.value!.estimatedAmount, - rateType: rateType, - rateId: response.value!.rateId, - ); - - if (mounted) { - ref - .read( - exchangeSendFromWalletIdStateProvider - .state) - .state = Tuple2(walletId, coin); - unawaited(Navigator.of(context).pushNamed( - Step2View.routeName, - arguments: model, - )); - } - } else { - final fromTicker = ref - .read(fixedRateExchangeFormProvider) - .market - ?.from ?? - ""; - final toTicker = ref - .read(fixedRateExchangeFormProvider) - .market - ?.to ?? - ""; - - final sendAmount = Decimal.parse(ref - .read(fixedRateExchangeFormProvider) - .fromAmountString); - - final rateType = ref - .read(prefsChangeNotifierProvider) - .exchangeRateType; - - final response = await ref - .read(changeNowProvider) - .getEstimate( - fromTicker, - toTicker, - sendAmount, - true, - false, - ); - - bool? shouldCancel; - - if (response.value == null) { - unawaited(showDialog<dynamic>( - context: context, - barrierDismissible: true, - builder: (_) => StackDialog( - title: - "Failed to update trade estimate", - message: - response.exception?.toString(), - ), - )); - return; - } else if (response.value!.warningMessage != - null && - response.value!.warningMessage! - .isNotEmpty) { - shouldCancel = await showDialog<bool?>( - context: context, - barrierDismissible: true, - builder: (_) => StackDialog( - title: - "Failed to update trade estimate", - message: - "${response.value!.warningMessage!}\n\nDo you want to attempt trade anyways?", - leftButton: TextButton( - style: Theme.of(context) - .extension<StackColors>()! - .getSecondaryEnabledButtonColor( - context), - child: Text( - "Cancel", - style: STextStyles.itemSubtitle12( - context), - ), - onPressed: () { - // notify return to cancel - Navigator.of(context).pop(true); - }, - ), - rightButton: TextButton( - style: Theme.of(context) - .extension<StackColors>()! - .getPrimaryEnabledButtonColor( - context), - child: Text( - "Attempt", - style: - STextStyles.button(context), - ), - onPressed: () { - // continue and try to attempt trade - Navigator.of(context).pop(false); - }, - ), - ), - ); - } - - if (shouldCancel is bool && shouldCancel) { - return; - } - - String rate = - "1 $fromTicker ~${ref.read(fixedRateExchangeFormProvider).rate!.toStringAsFixed(8)} $toTicker"; - - final model = IncompleteExchangeModel( - sendTicker: fromTicker, - receiveTicker: toTicker, - rateInfo: rate, - sendAmount: sendAmount, - receiveAmount: - response.value!.estimatedAmount, - rateType: rateType, - rateId: response.value!.rateId, - ); - - if (mounted) { - ref - .read( - exchangeSendFromWalletIdStateProvider - .state) - .state = Tuple2(walletId, coin); - unawaited(Navigator.of(context).pushNamed( - Step2View.routeName, - arguments: model, - )); - } - } - } - : null, - child: Text( - "Next", - style: STextStyles.button(context), - ), + ExchangeForm( + walletId: walletId, + coin: coin, ), ], ),