diff --git a/lib/models/exchange/aggregate_currency.dart b/lib/models/exchange/aggregate_currency.dart new file mode 100644 index 000000000..2cb4109aa --- /dev/null +++ b/lib/models/exchange/aggregate_currency.dart @@ -0,0 +1,26 @@ +import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; +import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; +import 'package:tuple/tuple.dart'; + +class AggregateCurrency { + final Map _map = {}; + + AggregateCurrency( + {required List> exchangeCurrencyPairs}) { + assert(exchangeCurrencyPairs.isNotEmpty); + + for (final item in exchangeCurrencyPairs) { + _map[item.item1] = item.item2; + } + } + + Currency? forExchange(String exchangeName) { + return _map[exchangeName]; + } + + String get ticker => _map.values.first!.ticker; + String get name => _map.values.first!.name; + String get image => _map.values.first!.image; + SupportedRateType get rateType => _map.values.first!.rateType; + bool get isStackCoin => _map.values.first!.isStackCoin; +} diff --git a/lib/models/exchange/exchange_form_state.dart b/lib/models/exchange/exchange_form_state.dart index 374875916..683f80abb 100644 --- a/lib/models/exchange/exchange_form_state.dart +++ b/lib/models/exchange/exchange_form_state.dart @@ -1,12 +1,9 @@ import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; -import 'package:isar/isar.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/models/exchange/response_objects/estimate.dart'; -import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; -import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/services/exchange/exchange.dart'; -import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/logger.dart'; class ExchangeFormState extends ChangeNotifier { @@ -51,15 +48,15 @@ class ExchangeFormState extends ChangeNotifier { // } - Currency? _sendCurrency; - Currency? get sendCurrency => _sendCurrency; + AggregateCurrency? _sendCurrency; + AggregateCurrency? get sendCurrency => _sendCurrency; // set sendCurrency(Currency? sendCurrency) { // _sendCurrency = sendCurrency; // // // } - Currency? _receiveCurrency; - Currency? get receiveCurrency => _receiveCurrency; + AggregateCurrency? _receiveCurrency; + AggregateCurrency? get receiveCurrency => _receiveCurrency; // set receiveCurrency(Currency? receiveCurrency) { // _receiveCurrency = receiveCurrency; // // @@ -111,8 +108,8 @@ class ExchangeFormState extends ChangeNotifier { receiveAmount != null && rate != null && rate! >= Decimal.zero && - exchange.name == sendCurrency!.exchangeName && - exchange.name == receiveCurrency!.exchangeName && + sendCurrency!.forExchange(exchange.name) != null && + receiveCurrency!.forExchange(exchange.name) != null && warning.isEmpty; } @@ -154,46 +151,6 @@ class ExchangeFormState extends ChangeNotifier { }) async { _exchange = exchange; if (shouldUpdateData) { - if (_sendCurrency != null) { - _sendCurrency = await ExchangeDataLoadingService - .instance.isar.currencies - .where() - .exchangeNameEqualTo(exchange.name) - .filter() - .tickerEqualTo(_sendCurrency!.ticker) - .and() - .group((q) => exchangeRateType == ExchangeRateType.fixed - ? q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.fixed) - : q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.estimated)) - .findFirst(); - } - - if (_receiveCurrency != null) { - _receiveCurrency = await ExchangeDataLoadingService - .instance.isar.currencies - .where() - .exchangeNameEqualTo(exchange.name) - .filter() - .tickerEqualTo(_receiveCurrency!.ticker) - .and() - .group((q) => exchangeRateType == ExchangeRateType.fixed - ? q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.fixed) - : q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.estimated)) - .findFirst(); - } - await _updateRangesAndEstimate( shouldNotifyListeners: false, ); @@ -204,7 +161,7 @@ class ExchangeFormState extends ChangeNotifier { } } - void setCurrencies(Currency from, Currency to) { + void setCurrencies(AggregateCurrency from, AggregateCurrency to) { _sendCurrency = from; _receiveCurrency = to; } @@ -282,7 +239,7 @@ class ExchangeFormState extends ChangeNotifier { } Future updateSendCurrency( - Currency sendCurrency, + AggregateCurrency sendCurrency, bool shouldNotifyListeners, ) async { try { @@ -306,7 +263,7 @@ class ExchangeFormState extends ChangeNotifier { } Future updateReceivingCurrency( - Currency receiveCurrency, + AggregateCurrency receiveCurrency, bool shouldNotifyListeners, ) async { try { @@ -341,7 +298,7 @@ class ExchangeFormState extends ChangeNotifier { _minReceiveAmount = null; _maxReceiveAmount = null; - final Currency? tmp = sendCurrency; + final AggregateCurrency? tmp = sendCurrency; _sendCurrency = receiveCurrency; _receiveCurrency = tmp; diff --git a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart index 1c36e139f..6d1956256 100644 --- a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart +++ b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart @@ -26,14 +26,14 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart'; class ExchangeCurrencySelectionView extends StatefulWidget { const ExchangeCurrencySelectionView({ Key? key, - required this.willChange, - required this.paired, + required this.willChangeTicker, + required this.pairedTicker, required this.isFixedRate, required this.willChangeIsSend, }) : super(key: key); - final Currency? willChange; - final Currency? paired; + final String? willChangeTicker; + final String? pairedTicker; final bool isFixedRate; final bool willChangeIsSend; @@ -87,7 +87,7 @@ class _ExchangeCurrencySelectionViewState } Future> _loadCurrencies() async { - if (widget.paired == null) { + if (widget.pairedTicker == null) { return await _getCurrencies(); } @@ -136,8 +136,8 @@ class _ExchangeCurrencySelectionViewState .rateTypeEqualTo(SupportedRateType.estimated)) .and() .group((q) => widget.willChangeIsSend - ? q.toEqualTo(widget.paired!.ticker, caseSensitive: false) - : q.fromEqualTo(widget.paired!.ticker, caseSensitive: false)); + ? q.toEqualTo(widget.pairedTicker!, caseSensitive: false) + : q.fromEqualTo(widget.pairedTicker!, caseSensitive: false)); if (widget.willChangeIsSend) { return query.sortByFrom().findAll(); @@ -170,7 +170,7 @@ class _ExchangeCurrencySelectionViewState return _currencies; } - if (widget.paired == null) { + if (widget.pairedTicker == null) { return _currencies .where((e) => e.name.toLowerCase().contains(text.toLowerCase()) || @@ -179,7 +179,7 @@ class _ExchangeCurrencySelectionViewState } else { return _currencies .where((e) => - e.ticker.toLowerCase() != widget.paired!.ticker.toLowerCase() && + e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase() && (e.name.toLowerCase().contains(text.toLowerCase()) || e.ticker.toLowerCase().contains(text.toLowerCase()))) .toList(growable: false); @@ -318,8 +318,7 @@ class _ExchangeCurrencySelectionViewState Flexible( child: Builder(builder: (context) { final coins = Coin.values.where((e) => - e.ticker.toLowerCase() != - widget.paired?.ticker.toLowerCase()); + e.ticker.toLowerCase() != widget.pairedTicker?.toLowerCase()); final items = filter(_searchString) .where((e) => coins diff --git a/lib/pages/exchange_view/exchange_form.dart b/lib/pages/exchange_view/exchange_form.dart index 701ecbf22..80db9758f 100644 --- a/lib/pages/exchange_view/exchange_form.dart +++ b/lib/pages/exchange_view/exchange_form.dart @@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/svg.dart'; import 'package:isar/isar.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; @@ -128,6 +129,35 @@ class _ExchangeFormState extends ConsumerState { }); } + Future _getAggregateCurrency(Currency currency) async { + final rateType = ref.read(prefsChangeNotifierProvider).exchangeRateType; + final currencies = await ExchangeDataLoadingService.instance.isar.currencies + .filter() + .group((q) => rateType == ExchangeRateType.fixed + ? q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.fixed) + : q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.estimated)) + .and() + .tickerEqualTo( + currency.ticker, + caseSensitive: false, + ) + .findAll(); + + final items = [Tuple2(currency.exchangeName, currency)]; + + for (final currency in currencies) { + items.add(Tuple2(currency.exchangeName, currency)); + } + + return AggregateCurrency(exchangeCurrencyPairs: items); + } + void selectSendCurrency() async { final type = (ref.read(prefsChangeNotifierProvider).exchangeRateType); final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? ""; @@ -139,17 +169,18 @@ class _ExchangeFormState extends ConsumerState { } final selectedCurrency = await _showCurrencySelectionSheet( - willChange: ref.read(exchangeFormStateProvider).sendCurrency, + willChange: ref.read(exchangeFormStateProvider).sendCurrency?.ticker, willChangeIsSend: true, - paired: ref.read(exchangeFormStateProvider).receiveCurrency, + paired: ref.read(exchangeFormStateProvider).receiveCurrency?.ticker, isFixedRate: type == ExchangeRateType.fixed, ); if (selectedCurrency != null) { await showUpdatingExchangeRate( - whileFuture: ref - .read(exchangeFormStateProvider) - .updateSendCurrency(selectedCurrency, true), + whileFuture: _getAggregateCurrency(selectedCurrency).then( + (aggregateSelected) => ref + .read(exchangeFormStateProvider) + .updateSendCurrency(aggregateSelected, true)), ); } } @@ -163,18 +194,19 @@ class _ExchangeFormState extends ConsumerState { } final selectedCurrency = await _showCurrencySelectionSheet( - willChange: ref.read(exchangeFormStateProvider).receiveCurrency, + willChange: ref.read(exchangeFormStateProvider).receiveCurrency?.ticker, willChangeIsSend: false, - paired: ref.read(exchangeFormStateProvider).sendCurrency, + paired: ref.read(exchangeFormStateProvider).sendCurrency?.ticker, isFixedRate: ref.read(prefsChangeNotifierProvider).exchangeRateType == ExchangeRateType.fixed, ); if (selectedCurrency != null) { await showUpdatingExchangeRate( - whileFuture: ref - .read(exchangeFormStateProvider) - .updateReceivingCurrency(selectedCurrency, true), + whileFuture: _getAggregateCurrency(selectedCurrency).then( + (aggregateSelected) => ref + .read(exchangeFormStateProvider) + .updateReceivingCurrency(aggregateSelected, true)), ); } } @@ -193,8 +225,8 @@ class _ExchangeFormState extends ConsumerState { } Future _showCurrencySelectionSheet({ - required Currency? willChange, - required Currency? paired, + required String? willChange, + required String? paired, required bool isFixedRate, required bool willChangeIsSend, }) async { @@ -241,8 +273,8 @@ class _ExchangeFormState extends ConsumerState { .extension()! .background, child: ExchangeCurrencySelectionView( - willChange: willChange, - paired: paired, + willChangeTicker: willChange, + pairedTicker: paired, isFixedRate: isFixedRate, willChangeIsSend: willChangeIsSend, ), @@ -259,8 +291,8 @@ class _ExchangeFormState extends ConsumerState { : await Navigator.of(context).push( MaterialPageRoute( builder: (_) => ExchangeCurrencySelectionView( - willChange: willChange, - paired: paired, + willChangeTicker: willChange, + pairedTicker: paired, isFixedRate: isFixedRate, willChangeIsSend: willChangeIsSend, ), @@ -292,57 +324,58 @@ class _ExchangeFormState extends ConsumerState { ref.read(exchangeFormStateProvider).reversed = false; if (!(toTicker == "-" || fromTicker == "-")) { - final available = await ExchangeDataLoadingService.instance.isar.pairs - .where() - .exchangeNameEqualTo( - ref.read(currentExchangeNameStateProvider.state).state) - .filter() - .fromEqualTo(fromTicker) - .and() - .toEqualTo(toTicker) - .findAll(); + // final available = await ExchangeDataLoadingService.instance.isar.pairs + // .where() + // .exchangeNameEqualTo( + // ref.read(currentExchangeNameStateProvider.state).state) + // .filter() + // .fromEqualTo(fromTicker) + // .and() + // .toEqualTo(toTicker) + // .findAll(); + await ref.read(exchangeFormStateProvider).refresh(); - if (available.isNotEmpty) { - final availableCurrencies = await ExchangeDataLoadingService - .instance.isar.currencies - .where() - .exchangeNameEqualTo( - ref.read(currentExchangeNameStateProvider.state).state) - .filter() - .tickerEqualTo(fromTicker) - .or() - .tickerEqualTo(toTicker) - .findAll(); - - if (availableCurrencies.length > 1) { - final from = - availableCurrencies.firstWhere((e) => e.ticker == fromTicker); - final to = - availableCurrencies.firstWhere((e) => e.ticker == toTicker); - - final newFromAmount = Decimal.tryParse(_sendController.text); - ref.read(exchangeFormStateProvider).receiveAmount = newFromAmount; - if (newFromAmount == null) { - _receiveController.text = ""; - } - - await ref - .read(exchangeFormStateProvider) - .updateReceivingCurrency(to, false); - await ref - .read(exchangeFormStateProvider) - .updateSendCurrency(from, true); - - _receiveController.text = - ref.read(exchangeFormStateProvider).toAmountString.isEmpty - ? "-" - : ref.read(exchangeFormStateProvider).toAmountString; - if (mounted) { - Navigator.of(context, rootNavigator: isDesktop).pop(); - } - return; - } - } + // if (available.isNotEmpty) { + // final availableCurrencies = await ExchangeDataLoadingService + // .instance.isar.currencies + // .where() + // .exchangeNameEqualTo( + // ref.read(currentExchangeNameStateProvider.state).state) + // .filter() + // .tickerEqualTo(fromTicker) + // .or() + // .tickerEqualTo(toTicker) + // .findAll(); + // + // if (availableCurrencies.length > 1) { + // final from = + // availableCurrencies.firstWhere((e) => e.ticker == fromTicker); + // final to = + // availableCurrencies.firstWhere((e) => e.ticker == toTicker); + // + // final newFromAmount = Decimal.tryParse(_sendController.text); + // ref.read(exchangeFormStateProvider).receiveAmount = newFromAmount; + // if (newFromAmount == null) { + // _receiveController.text = ""; + // } + // + // await ref + // .read(exchangeFormStateProvider) + // .updateReceivingCurrency(to, false); + // await ref + // .read(exchangeFormStateProvider) + // .updateSendCurrency(from, true); + // + // _receiveController.text = + // ref.read(exchangeFormStateProvider).toAmountString.isEmpty + // ? "-" + // : ref.read(exchangeFormStateProvider).toAmountString; + // if (mounted) { + // Navigator.of(context, rootNavigator: isDesktop).pop(); + // } + // return; + // } + // } } } diff --git a/lib/widgets/textfields/exchange_textfield.dart b/lib/widgets/textfields/exchange_textfield.dart index 44a210724..33fc6d738 100644 --- a/lib/widgets/textfields/exchange_textfield.dart +++ b/lib/widgets/textfields/exchange_textfield.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/pages/buy_view/sub_widgets/crypto_selection_view.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/text_styles.dart'; @@ -42,7 +42,7 @@ class ExchangeTextField extends StatefulWidget { final bool isWalletCoin; final bool readOnly; - final Currency? currency; + final AggregateCurrency? currency; @override State createState() => _ExchangeTextFieldState();